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.3 2007/11/07 00:43:24 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 struct hammer_cluster *
50 hammer_load_cluster(struct hammer_cluster *cluster, int *errorp,
52 static void initbuffer(hammer_alist_t live, hammer_fsbuf_head_t head,
54 static void alloc_new_buffer(struct hammer_cluster *cluster,
55 hammer_alist_t live, u_int64_t type, int32_t nelements,
57 int *errorp, struct hammer_buffer **bufferp);
59 static void readhammerbuf(struct hammer_volume *vol, void *data,
61 static void writehammerbuf(struct hammer_volume *vol, const void *data,
64 static int64_t calculate_cluster_offset(struct hammer_volume *vol,
66 static int64_t calculate_supercl_offset(struct hammer_volume *vol,
70 struct hammer_alist_config Buf_alist_config;
71 struct hammer_alist_config Vol_normal_alist_config;
72 struct hammer_alist_config Vol_super_alist_config;
73 struct hammer_alist_config Supercl_alist_config;
74 struct hammer_alist_config Clu_master_alist_config;
75 struct hammer_alist_config Clu_slave_alist_config;
78 * Red-Black tree support for various structures
81 hammer_ino_rb_compare(struct hammer_inode *ip1, struct hammer_inode *ip2)
83 if (ip1->obj_id < ip2->obj_id)
85 if (ip1->obj_id > ip2->obj_id)
87 if (ip1->obj_asof < ip2->obj_asof)
89 if (ip1->obj_asof > ip2->obj_asof)
95 hammer_inode_info_cmp(hammer_inode_info_t info, struct hammer_inode *ip)
97 if (info->obj_id < ip->obj_id)
99 if (info->obj_id > ip->obj_id)
101 if (info->obj_asof < ip->obj_asof)
103 if (info->obj_asof > ip->obj_asof)
109 hammer_vol_rb_compare(struct hammer_volume *vol1, struct hammer_volume *vol2)
111 if (vol1->vol_no < vol2->vol_no)
113 if (vol1->vol_no > vol2->vol_no)
119 hammer_scl_rb_compare(struct hammer_supercl *cl1, struct hammer_supercl *cl2)
121 if (cl1->scl_no < cl2->scl_no)
123 if (cl1->scl_no > cl2->scl_no)
129 hammer_clu_rb_compare(struct hammer_cluster *cl1, struct hammer_cluster *cl2)
131 if (cl1->clu_no < cl2->clu_no)
133 if (cl1->clu_no > cl2->clu_no)
139 hammer_buf_rb_compare(struct hammer_buffer *buf1, struct hammer_buffer *buf2)
141 if (buf1->buf_no < buf2->buf_no)
143 if (buf1->buf_no > buf2->buf_no)
149 * Note: The lookup function for hammer_ino_rb_tree winds up being named
150 * hammer_ino_rb_tree_RB_LOOKUP_INFO(root, info). The other lookup
151 * functions are normal, e.g. hammer_clu_rb_tree_RB_LOOKUP(root, clu_no).
153 RB_GENERATE(hammer_ino_rb_tree, hammer_inode, rb_node, hammer_ino_rb_compare);
154 RB_GENERATE_XLOOKUP(hammer_ino_rb_tree, INFO, hammer_inode, rb_node,
155 hammer_inode_info_cmp, hammer_inode_info_t);
156 RB_GENERATE2(hammer_vol_rb_tree, hammer_volume, rb_node,
157 hammer_vol_rb_compare, int32_t, vol_no);
158 RB_GENERATE2(hammer_scl_rb_tree, hammer_supercl, rb_node,
159 hammer_scl_rb_compare, int32_t, scl_no);
160 RB_GENERATE2(hammer_clu_rb_tree, hammer_cluster, rb_node,
161 hammer_clu_rb_compare, int32_t, clu_no);
162 RB_GENERATE2(hammer_buf_rb_tree, hammer_buffer, rb_node,
163 hammer_buf_rb_compare, int32_t, buf_no);
166 * Load a HAMMER volume by name. Returns 0 on success or a positive error
167 * code on failure. Volumes must be loaded at mount time, get_volume() will
168 * not load a new volume.
170 * Calls made to hammer_load_volume() or single-threaded
173 hammer_load_volume(struct hammer_mount *hmp, const char *volname)
176 struct hammer_volume *volume;
177 struct hammer_volume_ondisk *ondisk;
178 struct nlookupdata nd;
179 struct buf *bp = NULL;
184 ronly = ((mp->mnt_flag & MNT_RDONLY) ? 1 : 0);
187 * Allocate a volume structure
189 volume = kmalloc(sizeof(*volume), M_HAMMER, M_WAITOK|M_ZERO);
190 volume->vol_name = kstrdup(volname, M_HAMMER);
192 volume->io.type = HAMMER_STRUCTURE_VOLUME;
193 volume->io.offset = 0LL;
196 * Get the device vnode
198 error = nlookup_init(&nd, volume->vol_name, UIO_SYSSPACE, NLC_FOLLOW);
200 error = nlookup(&nd);
202 error = cache_vref(&nd.nl_nch, nd.nl_cred, &volume->devvp);
205 vn_isdisk(volume->devvp, &error);
208 vn_lock(volume->devvp, LK_EXCLUSIVE | LK_RETRY);
209 error = VOP_OPEN(volume->devvp, (ronly ? FREAD : FREAD|FWRITE),
211 vn_unlock(volume->devvp);
214 hammer_free_volume(volume);
219 * Extract the volume number from the volume header and do various
222 error = bread(volume->devvp, 0LL, HAMMER_BUFSIZE, &bp);
225 ondisk = (void *)bp->b_data;
226 if (ondisk->head.buf_type != HAMMER_FSBUF_VOLUME) {
227 kprintf("hammer_mount: volume %s has an invalid header\n",
232 volume->vol_no = ondisk->vol_no;
233 volume->cluster_base = ondisk->vol_beg;
234 volume->vol_clsize = ondisk->vol_clsize;
235 volume->vol_flags = ondisk->vol_flags;
236 RB_INIT(&volume->rb_clus_root);
237 RB_INIT(&volume->rb_scls_root);
239 if (RB_EMPTY(&hmp->rb_vols_root)) {
240 hmp->fsid = ondisk->vol_fsid;
241 } else if (bcmp(&hmp->fsid, &ondisk->vol_fsid, sizeof(uuid_t))) {
242 kprintf("hammer_mount: volume %s's fsid does not match "
243 "other volumes\n", volume->vol_name);
249 * Insert the volume structure into the red-black tree.
251 if (RB_INSERT(hammer_vol_rb_tree, &hmp->rb_vols_root, volume)) {
252 kprintf("hammer_mount: volume %s has a duplicate vol_no %d\n",
253 volume->vol_name, volume->vol_no);
258 * Set the root volume and load the root cluster. HAMMER special
259 * cases rootvol and rootcl and will not deallocate the structures.
261 if (error == 0 && ondisk->vol_rootvol == ondisk->vol_no) {
262 hmp->rootvol = volume;
263 hmp->rootcl = hammer_get_cluster(volume,
264 ondisk->vol0_root_clu_no,
266 hammer_put_cluster(hmp->rootcl, 0);
267 hmp->fsid_udev = dev2udev(vn_todev(volume->devvp));
273 /*vinvalbuf(volume->devvp, V_SAVE, 0, 0);*/
274 VOP_CLOSE(volume->devvp, ronly ? FREAD : FREAD|FWRITE);
275 hammer_free_volume(volume);
281 * Unload and free a HAMMER volume. Must return >= 0 to continue scan
282 * so returns -1 on failure.
285 hammer_unload_volume(struct hammer_volume *volume, void *data __unused)
287 struct hammer_mount *hmp = volume->hmp;
288 struct hammer_cluster *rootcl;
289 int ronly = ((hmp->mp->mnt_flag & MNT_RDONLY) ? 1 : 0);
292 * Sync clusters, sync volume
296 * Clean up the root cluster, which is held unlocked in the root
299 if (hmp->rootvol == volume) {
300 if ((rootcl = hmp->rootcl) != NULL) {
301 hammer_lock(&rootcl->io.lock);
303 hammer_put_cluster(rootcl, 1);
311 hammer_io_release(&volume->io, 1);
312 volume->ondisk = NULL;
315 vinvalbuf(volume->devvp, 0, 0, 0);
316 VOP_CLOSE(volume->devvp, FREAD);
318 vinvalbuf(volume->devvp, V_SAVE, 0, 0);
319 VOP_CLOSE(volume->devvp, FREAD|FWRITE);
324 * Destroy the structure
326 RB_REMOVE(hammer_vol_rb_tree, &hmp->rb_vols_root, volume);
327 hammer_free_volume(volume);
333 hammer_free_volume(struct hammer_volume *volume)
335 if (volume->vol_name) {
336 kfree(volume->vol_name, M_HAMMER);
337 volume->vol_name = NULL;
340 vrele(volume->devvp);
341 volume->devvp = NULL;
343 kfree(volume, M_HAMMER);
347 * Get a HAMMER volume. The volume must already exist.
349 struct hammer_volume *
350 hammer_get_volume(struct hammer_mount *hmp, int32_t vol_no, int *errorp)
352 struct hammer_volume *volume;
353 struct hammer_volume_ondisk *ondisk;
356 * Locate the volume structure
358 volume = RB_LOOKUP(hammer_vol_rb_tree, &hmp->rb_vols_root, vol_no);
359 if (volume == NULL) {
365 * Load the ondisk buffer if necessary. Create a b_dep dependancy
366 * for the buffer that allows us to manage our structure with the
367 * buffer (mostly) left in a released state.
369 hammer_lock(&volume->io.lock);
370 if (volume->ondisk == NULL) {
371 *errorp = hammer_io_read(volume->devvp, &volume->io);
373 hammer_unlock(&volume->io.lock);
376 volume->ondisk = ondisk = (void *)volume->io.bp->b_data;
379 * Configure the volume's A-lists. These are used to
382 if (volume->vol_flags & HAMMER_VOLF_USINGSUPERCL) {
383 volume->alist.config = &Vol_super_alist_config;
384 volume->alist.meta = ondisk->vol_almeta.super;
385 volume->alist.info = volume;
387 volume->alist.config = &Vol_normal_alist_config;
388 volume->alist.meta = ondisk->vol_almeta.normal;
389 volume->alist.info = NULL;
391 hammer_alist_init(&volume->alist);
398 * Unlock and release a volume.
400 * Buffer cache interactions (applies to volumes, superclusters, clusters,
401 * and buffer structures):
405 hammer_put_volume(struct hammer_volume *volume, int flush)
407 if (hammer_islastref(&volume->io.lock)) {
408 hammer_io_release(&volume->io, flush);
410 hammer_unlock(&volume->io.lock);
414 struct hammer_supercl *
415 hammer_get_supercl(struct hammer_volume *volume, int32_t scl_no,
416 int *errorp, int isnew)
418 struct hammer_supercl_ondisk *ondisk;
419 struct hammer_supercl *supercl;
422 * Locate and lock the super-cluster structure, creating one
426 supercl = RB_LOOKUP(hammer_scl_rb_tree, &volume->rb_scls_root, scl_no);
427 if (supercl == NULL) {
428 supercl = kmalloc(sizeof(*supercl), M_HAMMER, M_WAITOK|M_ZERO);
429 supercl->scl_no = scl_no;
430 supercl->volume = volume;
431 supercl->io.offset = calculate_supercl_offset(volume, scl_no);
432 supercl->io.type = HAMMER_STRUCTURE_SUPERCL;
433 hammer_lock(&supercl->io.lock);
436 * Insert the cluster into the RB tree and handle late
439 if (RB_INSERT(hammer_scl_rb_tree, &volume->rb_scls_root, supercl)) {
440 hammer_unlock(&supercl->io.lock);
441 kfree(supercl, M_HAMMER);
444 hammer_ref(&volume->io.lock);
446 hammer_lock(&supercl->io.lock);
450 * Load the cluster's on-disk info
453 if (supercl->ondisk == NULL) {
455 *errorp = hammer_io_new(volume->devvp, &supercl->io);
457 *errorp = hammer_io_read(volume->devvp, &supercl->io);
459 hammer_put_supercl(supercl, 1);
462 supercl->ondisk = ondisk = (void *)supercl->io.bp->b_data;
464 supercl->alist.config = &Supercl_alist_config;
465 supercl->alist.meta = ondisk->scl_meta;
466 supercl->alist.info = NULL;
469 * If this is a new super-cluster we have to initialize
470 * various ondisk structural elements. The caller is
471 * responsible for the remainder.
474 struct hammer_alist_live dummy;
476 dummy.config = &Buf_alist_config;
477 dummy.meta = ondisk->head.buf_almeta;
479 initbuffer(&dummy, &ondisk->head, HAMMER_FSBUF_SUPERCL);
480 hammer_alist_init(&supercl->alist);
483 *errorp = hammer_io_new(volume->devvp, &supercl->io);
485 hammer_put_supercl(supercl, 1);
493 hammer_put_supercl(struct hammer_supercl *supercl, int flush)
495 struct hammer_volume *volume;
497 if (hammer_islastref(&supercl->io.lock)) {
498 volume = supercl->volume;
499 hammer_io_release(&supercl->io, flush);
500 if (supercl->io.bp == NULL &&
501 hammer_islastref(&supercl->io.lock)) {
502 RB_REMOVE(hammer_scl_rb_tree,
503 &volume->rb_scls_root, supercl);
504 kfree(supercl, M_HAMMER);
505 if (hammer_islastref(&volume->io.lock)) {
506 hammer_ref_to_lock(&volume->io.lock);
507 hammer_put_volume(volume, 0);
511 hammer_unlock(&supercl->io.lock);
515 struct hammer_cluster *
516 hammer_get_cluster(struct hammer_volume *volume, int32_t clu_no,
517 int *errorp, int isnew)
519 struct hammer_cluster *cluster;
522 * Locate and lock the cluster structure, creating one if necessary.
525 cluster = RB_LOOKUP(hammer_clu_rb_tree, &volume->rb_clus_root, clu_no);
526 if (cluster == NULL) {
527 cluster = kmalloc(sizeof(*cluster), M_HAMMER, M_WAITOK|M_ZERO);
528 cluster->clu_no = clu_no;
529 cluster->volume = volume;
530 cluster->io.offset = calculate_cluster_offset(volume, clu_no);
531 RB_INIT(&cluster->rb_bufs_root);
532 cluster->io.type = HAMMER_STRUCTURE_CLUSTER;
533 hammer_lock(&cluster->io.lock);
536 * Insert the cluster into the RB tree and handle late
539 if (RB_INSERT(hammer_clu_rb_tree, &volume->rb_clus_root, cluster)) {
540 hammer_unlock(&cluster->io.lock);
541 kfree(cluster, M_HAMMER);
544 hammer_ref(&volume->io.lock);
546 hammer_lock(&cluster->io.lock);
548 return(hammer_load_cluster(cluster, errorp, isnew));
551 struct hammer_cluster *
552 hammer_get_rootcl(struct hammer_mount *hmp)
554 struct hammer_cluster *cluster = hmp->rootcl;
557 hammer_lock(&cluster->io.lock);
558 return(hammer_load_cluster(cluster, &dummy_error, 0));
563 struct hammer_cluster *
564 hammer_load_cluster(struct hammer_cluster *cluster, int *errorp, int isnew)
566 struct hammer_volume *volume = cluster->volume;
567 struct hammer_cluster_ondisk *ondisk;
570 * Load the cluster's on-disk info
573 if (cluster->ondisk == NULL) {
575 *errorp = hammer_io_new(volume->devvp, &cluster->io);
577 *errorp = hammer_io_read(volume->devvp, &cluster->io);
579 hammer_put_cluster(cluster, 1);
582 cluster->ondisk = ondisk = (void *)cluster->io.bp->b_data;
584 cluster->alist_master.config = &Clu_master_alist_config;
585 cluster->alist_master.meta = ondisk->clu_master_meta;
586 cluster->alist_btree.config = &Clu_slave_alist_config;
587 cluster->alist_btree.meta = ondisk->clu_btree_meta;
588 cluster->alist_btree.info = cluster;
589 cluster->alist_record.config = &Clu_slave_alist_config;
590 cluster->alist_record.meta = ondisk->clu_record_meta;
591 cluster->alist_record.info = cluster;
592 cluster->alist_mdata.config = &Clu_slave_alist_config;
593 cluster->alist_mdata.meta = ondisk->clu_mdata_meta;
594 cluster->alist_mdata.info = cluster;
597 * If this is a new cluster we have to initialize
598 * various ondisk structural elements. The caller is
599 * responsible for the remainder.
602 struct hammer_alist_live dummy;
604 dummy.config = &Buf_alist_config;
605 dummy.meta = ondisk->head.buf_almeta;
607 initbuffer(&dummy, &ondisk->head, HAMMER_FSBUF_CLUSTER);
609 hammer_alist_init(&cluster->alist_master);
610 hammer_alist_init(&cluster->alist_btree);
611 hammer_alist_init(&cluster->alist_record);
612 hammer_alist_init(&cluster->alist_mdata);
615 *errorp = hammer_io_new(volume->devvp, &cluster->io);
617 hammer_put_cluster(cluster, 1);
625 hammer_put_cluster(struct hammer_cluster *cluster, int flush)
627 struct hammer_volume *volume;
629 if (hammer_islastref(&cluster->io.lock)) {
630 volume = cluster->volume;
631 hammer_io_release(&cluster->io, flush);
632 if (cluster->io.bp == NULL &&
633 volume->hmp->rootcl != cluster &&
634 hammer_islastref(&cluster->io.lock)) {
635 RB_REMOVE(hammer_clu_rb_tree,
636 &volume->rb_clus_root, cluster);
637 kfree(cluster, M_HAMMER);
638 if (hammer_islastref(&volume->io.lock)) {
639 hammer_ref_to_lock(&volume->io.lock);
640 hammer_put_volume(volume, 0);
644 hammer_unlock(&cluster->io.lock);
649 * Get a buffer from a cluster. Note that buffer #0 is the cluster header
650 * itself and may not be retrieved with this function.
652 * If buf_type is 0 the buffer already exists in-memory or on-disk.
653 * Otherwise a new buffer is initialized with the specified buffer type.
655 struct hammer_buffer *
656 hammer_get_buffer(struct hammer_cluster *cluster, int32_t buf_no,
657 int64_t buf_type, int *errorp)
659 hammer_fsbuf_ondisk_t ondisk;
660 struct hammer_buffer *buffer;
663 * Find the buffer. Note that buffer 0 corresponds to the cluster
664 * header and should never be requested.
666 KKASSERT(buf_no != 0);
669 * Locate and lock the buffer structure, creating one if necessary.
672 buffer = RB_LOOKUP(hammer_buf_rb_tree, &cluster->rb_bufs_root, buf_no);
673 if (buffer == NULL) {
674 buffer = kmalloc(sizeof(*cluster), M_HAMMER, M_WAITOK|M_ZERO);
675 buffer->buf_no = buf_no;
676 buffer->cluster = cluster;
677 buffer->volume = cluster->volume;
678 buffer->io.offset = cluster->io.offset +
679 (buf_no * HAMMER_BUFSIZE);
680 buffer->io.type = HAMMER_STRUCTURE_BUFFER;
681 hammer_lock(&buffer->io.lock);
684 * Insert the cluster into the RB tree and handle late
687 if (RB_INSERT(hammer_buf_rb_tree, &cluster->rb_bufs_root, buffer)) {
688 hammer_unlock(&buffer->io.lock);
689 kfree(buffer, M_HAMMER);
692 hammer_ref(&cluster->io.lock);
694 hammer_lock(&buffer->io.lock);
698 if (buffer->ondisk == NULL) {
700 *errorp = hammer_io_new(buffer->volume->devvp,
703 *errorp = hammer_io_read(buffer->volume->devvp,
707 hammer_put_buffer(buffer, 1);
710 buffer->ondisk = ondisk = (void *)buffer->io.bp->b_data;
711 buffer->alist.config = &Buf_alist_config;
712 buffer->alist.meta = ondisk->head.buf_almeta;
715 initbuffer(&buffer->alist, &ondisk->head, buf_type);
717 } else if (buf_type) {
718 *errorp = hammer_io_new(buffer->volume->devvp,
721 hammer_put_buffer(buffer, 1);
729 hammer_put_buffer(struct hammer_buffer *buffer, int flush)
731 struct hammer_cluster *cluster;
733 if (hammer_islastref(&buffer->io.lock)) {
734 hammer_io_release(&buffer->io, flush);
735 if (buffer->io.bp == NULL &&
736 hammer_islastref(&buffer->io.lock)) {
737 RB_REMOVE(hammer_buf_rb_tree,
738 &buffer->cluster->rb_bufs_root, buffer);
739 cluster = buffer->cluster;
740 kfree(buffer, M_HAMMER);
741 if (hammer_islastref(&cluster->io.lock)) {
742 hammer_ref_to_lock(&cluster->io.lock);
743 hammer_put_cluster(cluster, 0);
747 hammer_unlock(&buffer->io.lock);
752 hammer_dup_buffer(struct hammer_buffer **bufferp, struct hammer_buffer *buffer)
754 if (buffer != *bufferp) {
756 hammer_lock(&buffer->io.lock);
758 hammer_put_buffer(*bufferp, 0);
764 hammer_dup_cluster(struct hammer_cluster **clusterp,
765 struct hammer_cluster *cluster)
767 if (cluster != *clusterp) {
769 hammer_lock(&cluster->io.lock);
771 hammer_put_cluster(*clusterp, 0);
777 * Allocate HAMMER elements - btree nodes, data storage, and record elements
779 * The passed *bufferp should be initialized to NULL. On successive calls
780 * *bufferp caches the most recent buffer used until put away by the caller.
781 * Note that previously returned pointers using the cached buffer become
782 * invalid on successive calls which reuse *bufferp.
784 * All allocations first attempt to use the block found at the specified
785 * iterator. If that fails the first available block is used. If that
786 * fails a new buffer is allocated and associated with the buffer type
787 * A-list and the element is allocated out of the new buffer.
790 hammer_alloc_btree(struct hammer_cluster *cluster,
791 int *errorp, struct hammer_buffer **bufferp)
793 struct hammer_buffer *buffer;
800 * Allocate a B-Tree element
802 live = &cluster->alist_btree;
803 elm_no = hammer_alist_alloc_fwd(live, 1, cluster->ondisk->idx_index);
804 if (elm_no == HAMMER_ALIST_BLOCK_NONE)
805 elm_no = hammer_alist_alloc_fwd(live, 1, 0);
806 if (elm_no == HAMMER_ALIST_BLOCK_NONE) {
807 alloc_new_buffer(cluster, live,
808 HAMMER_FSBUF_BTREE, HAMMER_BTREE_NODES,
809 cluster->ondisk->idx_index, errorp, bufferp);
810 elm_no = hammer_alist_alloc(live, 1);
811 if (elm_no == HAMMER_ALIST_BLOCK_NONE) {
816 cluster->ondisk->idx_index = elm_no;
819 * Load and return the B-Tree element
821 buf_no = elm_no / HAMMER_FSBUF_MAXBLKS;
823 if (buffer == NULL || buffer->cluster != cluster ||
824 buffer->buf_no != buf_no) {
826 hammer_put_buffer(buffer, 0);
827 buffer = hammer_get_buffer(cluster, buf_no, 0, errorp);
830 KKASSERT(buffer->ondisk->head.buf_type == HAMMER_FSBUF_BTREE);
831 item = &buffer->ondisk->btree.nodes[elm_no & HAMMER_FSBUF_BLKMASK];
832 bzero(item, sizeof(union hammer_btree_node));
838 hammer_alloc_data(struct hammer_cluster *cluster, int32_t bytes,
839 int *errorp, struct hammer_buffer **bufferp)
841 struct hammer_buffer *buffer;
849 * Allocate a data element
851 nblks = (bytes + HAMMER_DATA_BLKMASK) & ~HAMMER_DATA_BLKMASK;
852 live = &cluster->alist_mdata;
853 elm_no = hammer_alist_alloc_fwd(live, nblks, cluster->ondisk->idx_data);
854 if (elm_no == HAMMER_ALIST_BLOCK_NONE)
855 elm_no = hammer_alist_alloc_fwd(live, 1, 0);
856 if (elm_no == HAMMER_ALIST_BLOCK_NONE) {
857 alloc_new_buffer(cluster, live,
858 HAMMER_FSBUF_DATA, HAMMER_DATA_NODES,
859 cluster->ondisk->idx_data, errorp, bufferp);
860 elm_no = hammer_alist_alloc(live, nblks);
861 if (elm_no == HAMMER_ALIST_BLOCK_NONE) {
866 cluster->ondisk->idx_index = elm_no;
869 * Load and return the B-Tree element
871 buf_no = elm_no / HAMMER_FSBUF_MAXBLKS;
873 if (buffer == NULL || buffer->cluster != cluster ||
874 buffer->buf_no != buf_no) {
876 hammer_put_buffer(buffer, 0);
877 buffer = hammer_get_buffer(cluster, buf_no, 0, errorp);
880 KKASSERT(buffer->ondisk->head.buf_type == HAMMER_FSBUF_BTREE);
881 item = &buffer->ondisk->data.data[elm_no & HAMMER_FSBUF_BLKMASK];
882 bzero(item, nblks * HAMMER_DATA_BLKSIZE);
888 hammer_alloc_record(struct hammer_cluster *cluster,
889 int *errorp, struct hammer_buffer **bufferp)
891 struct hammer_buffer *buffer;
898 * Allocate a record element
900 live = &cluster->alist_record;
901 elm_no = hammer_alist_alloc_rev(live, 1, cluster->ondisk->idx_record);
902 if (elm_no == HAMMER_ALIST_BLOCK_NONE)
903 elm_no = hammer_alist_alloc_rev(live, 1,HAMMER_ALIST_BLOCK_MAX);
904 if (elm_no == HAMMER_ALIST_BLOCK_NONE) {
905 alloc_new_buffer(cluster, live,
906 HAMMER_FSBUF_RECORDS, HAMMER_RECORD_NODES,
907 cluster->ondisk->idx_record, errorp, bufferp);
908 elm_no = hammer_alist_alloc(live, 1);
909 if (elm_no == HAMMER_ALIST_BLOCK_NONE) {
914 cluster->ondisk->idx_record = elm_no;
917 * Load and return the B-Tree element
919 buf_no = elm_no / HAMMER_FSBUF_MAXBLKS;
921 if (buffer == NULL || buffer->cluster != cluster ||
922 buffer->buf_no != buf_no) {
924 hammer_put_buffer(buffer, 0);
925 buffer = hammer_get_buffer(cluster, buf_no, 0, errorp);
928 KKASSERT(buffer->ondisk->head.buf_type != 0);
929 item = &buffer->ondisk->record.recs[elm_no & HAMMER_FSBUF_BLKMASK];
930 bzero(item, sizeof(union hammer_record_ondisk));
936 * Free HAMMER elements based on either a hammer_buffer and element pointer
937 * or a cluster-relative byte offset.
940 hammer_free_btree_ptr(struct hammer_buffer *buffer, hammer_btree_node_t node)
945 elm_no = node - buffer->ondisk->btree.nodes;
946 KKASSERT(elm_no >= 0 && elm_no < HAMMER_BTREE_NODES);
947 elm_no += buffer->buf_no * HAMMER_FSBUF_MAXBLKS;
948 live = &buffer->cluster->alist_btree;
949 hammer_alist_free(live, elm_no, 1);
953 hammer_free_data_ptr(struct hammer_buffer *buffer, void *data, int bytes)
959 elm_no = ((char *)data - (char *)buffer->ondisk->data.data) /
961 KKASSERT(elm_no >= 0 && elm_no < HAMMER_DATA_NODES);
962 elm_no += buffer->buf_no * HAMMER_FSBUF_MAXBLKS;
963 nblks = (bytes + HAMMER_DATA_BLKMASK) & ~HAMMER_DATA_BLKMASK;
964 live = &buffer->cluster->alist_mdata;
965 hammer_alist_free(live, elm_no, nblks);
969 hammer_free_record_ptr(struct hammer_buffer *buffer,
970 union hammer_record_ondisk *rec)
975 elm_no = rec - &buffer->ondisk->record.recs[0];
976 KKASSERT(elm_no >= 0 && elm_no < HAMMER_BTREE_NODES);
977 elm_no += buffer->buf_no * HAMMER_FSBUF_MAXBLKS;
978 live = &buffer->cluster->alist_record;
979 hammer_alist_free(live, elm_no, 1);
983 hammer_free_btree(struct hammer_cluster *cluster, int32_t bclu_offset)
985 const int32_t blksize = sizeof(union hammer_btree_node);
986 int32_t fsbuf_offset = bclu_offset & HAMMER_BUFMASK;
990 elm_no = bclu_offset / HAMMER_BUFSIZE * HAMMER_FSBUF_MAXBLKS;
991 fsbuf_offset -= offsetof(union hammer_fsbuf_ondisk, btree.nodes[0]);
992 live = &cluster->alist_btree;
993 KKASSERT(fsbuf_offset >= 0 && fsbuf_offset % blksize == 0);
994 elm_no += fsbuf_offset / blksize;
995 hammer_alist_free(live, elm_no, 1);
999 hammer_free_data(struct hammer_cluster *cluster, int32_t bclu_offset,
1002 const int32_t blksize = HAMMER_DATA_BLKSIZE;
1003 int32_t fsbuf_offset = bclu_offset & HAMMER_BUFMASK;
1004 hammer_alist_t live;
1008 elm_no = bclu_offset / HAMMER_BUFSIZE * HAMMER_FSBUF_MAXBLKS;
1009 fsbuf_offset -= offsetof(union hammer_fsbuf_ondisk, data.data[0][0]);
1010 live = &cluster->alist_mdata;
1011 nblks = (bytes + HAMMER_DATA_BLKMASK) & ~HAMMER_DATA_BLKMASK;
1012 KKASSERT(fsbuf_offset >= 0 && fsbuf_offset % blksize == 0);
1013 elm_no += fsbuf_offset / blksize;
1014 hammer_alist_free(live, elm_no, nblks);
1018 hammer_free_record(struct hammer_cluster *cluster, int32_t bclu_offset)
1020 const int32_t blksize = sizeof(union hammer_record_ondisk);
1021 int32_t fsbuf_offset = bclu_offset & HAMMER_BUFMASK;
1022 hammer_alist_t live;
1025 elm_no = bclu_offset / HAMMER_BUFSIZE * HAMMER_FSBUF_MAXBLKS;
1026 fsbuf_offset -= offsetof(union hammer_fsbuf_ondisk, record.recs[0]);
1027 live = &cluster->alist_record;
1028 KKASSERT(fsbuf_offset >= 0 && fsbuf_offset % blksize == 0);
1029 elm_no += fsbuf_offset / blksize;
1030 hammer_alist_free(live, elm_no, 1);
1035 * Allocate a new filesystem buffer and assign it to the specified
1036 * filesystem buffer type. The new buffer will be added to the
1037 * type-specific A-list and initialized.
1040 alloc_new_buffer(struct hammer_cluster *cluster, hammer_alist_t live,
1041 u_int64_t type, int32_t nelements,
1042 int start, int *errorp, struct hammer_buffer **bufferp)
1044 struct hammer_buffer *buffer;
1047 start = start / HAMMER_FSBUF_MAXBLKS; /* convert to buf_no */
1049 if (type == HAMMER_FSBUF_RECORDS) {
1050 buf_no = hammer_alist_alloc_rev(&cluster->alist_master,
1052 if (buf_no == HAMMER_ALIST_BLOCK_NONE) {
1053 buf_no = hammer_alist_alloc_rev(&cluster->alist_master,
1054 1, HAMMER_ALIST_BLOCK_MAX);
1057 buf_no = hammer_alist_alloc_fwd(&cluster->alist_master,
1059 if (buf_no == HAMMER_ALIST_BLOCK_NONE) {
1060 buf_no = hammer_alist_alloc_fwd(&cluster->alist_master,
1064 KKASSERT(buf_no != HAMMER_ALIST_BLOCK_NONE); /* XXX */
1067 * The new buffer must be initialized (type != 0) regardless of
1068 * whether we already have it cached or not, so don't try to
1069 * optimize the cached buffer check. Just call hammer_get_buffer().
1071 buffer = hammer_get_buffer(cluster, buf_no, type, errorp);
1073 hammer_put_buffer(*bufferp, 0);
1080 * Flush various tracking structures to disk
1084 * Flush various tracking structures to disk
1087 flush_all_volumes(void)
1089 struct hammer_volume *vol;
1091 for (vol = VolBase; vol; vol = vol->next)
1096 flush_volume(struct hammer_volume *vol)
1098 struct hammer_supercl *supercl;
1099 struct hammer_cluster *cl;
1101 for (supercl = vol->supercl_base; supercl; supercl = supercl->next)
1102 flush_supercl(supercl);
1103 for (cl = vol->cluster_base; cl; cl = cl->next)
1105 writehammerbuf(vol, vol->ondisk, 0);
1109 flush_supercl(struct hammer_supercl *supercl)
1111 int64_t supercl_offset;
1113 supercl_offset = supercl->scl_offset;
1114 writehammerbuf(supercl->volume, supercl->ondisk, supercl_offset);
1118 flush_cluster(struct hammer_cluster *cl)
1120 struct hammer_buffer *buf;
1121 int64_t cluster_offset;
1123 for (buf = cl->buffer_base; buf; buf = buf->next)
1125 cluster_offset = cl->clu_offset;
1126 writehammerbuf(cl->volume, cl->ondisk, cluster_offset);
1130 flush_buffer(struct hammer_buffer *buf)
1132 int64_t buffer_offset;
1134 buffer_offset = buf->buf_offset + buf->cluster->clu_offset;
1135 writehammerbuf(buf->volume, buf->ondisk, buffer_offset);
1141 * Generic buffer initialization
1144 initbuffer(hammer_alist_t live, hammer_fsbuf_head_t head, u_int64_t type)
1146 head->buf_type = type;
1147 hammer_alist_init(live);
1151 * Calculate the cluster's offset in the volume. This calculation is
1152 * slightly more complex when using superclusters because superclusters
1153 * are grouped in blocks of 16, followed by 16 x N clusters where N
1154 * is the number of clusters a supercluster can manage.
1157 calculate_cluster_offset(struct hammer_volume *volume, int32_t clu_no)
1160 int64_t scl_group_size;
1163 if (volume->vol_flags & HAMMER_VOLF_USINGSUPERCL) {
1164 scl_group = clu_no / HAMMER_VOL_SUPERCLUSTER_GROUP /
1165 HAMMER_SCL_MAXCLUSTERS;
1167 ((int64_t)HAMMER_BUFSIZE *
1168 HAMMER_VOL_SUPERCLUSTER_GROUP) +
1169 ((int64_t)HAMMER_VOL_SUPERCLUSTER_GROUP *
1170 volume->vol_clsize * HAMMER_SCL_MAXCLUSTERS);
1172 HAMMER_VOL_SUPERCLUSTER_GROUP * HAMMER_BUFSIZE;
1174 off = volume->cluster_base +
1175 scl_group * scl_group_size +
1176 (HAMMER_BUFSIZE * HAMMER_VOL_SUPERCLUSTER_GROUP) +
1177 ((int64_t)clu_no % ((int64_t)HAMMER_SCL_MAXCLUSTERS *
1178 HAMMER_VOL_SUPERCLUSTER_GROUP))
1181 off = volume->cluster_base +
1182 (int64_t)clu_no * volume->vol_clsize;
1188 * Calculate a super-cluster's offset in the volume.
1191 calculate_supercl_offset(struct hammer_volume *volume, int32_t scl_no)
1195 int64_t scl_group_size;
1197 KKASSERT (volume->vol_flags & HAMMER_VOLF_USINGSUPERCL);
1198 scl_group = scl_no / HAMMER_VOL_SUPERCLUSTER_GROUP;
1201 ((int64_t)HAMMER_BUFSIZE *
1202 HAMMER_VOL_SUPERCLUSTER_GROUP) +
1203 ((int64_t)HAMMER_VOL_SUPERCLUSTER_GROUP *
1204 volume->vol_clsize * HAMMER_SCL_MAXCLUSTERS);
1206 HAMMER_VOL_SUPERCLUSTER_GROUP * HAMMER_BUFSIZE;
1207 off = volume->cluster_base + (scl_group * scl_group_size) +
1208 (scl_no % HAMMER_VOL_SUPERCLUSTER_GROUP) * HAMMER_BUFSIZE;
1210 off = volume->cluster_base + (scl_no * HAMMER_BUFSIZE);
1218 * Setup the parameters for the various A-lists we use in hammer. The
1219 * supercluster A-list must be chained to the cluster A-list and cluster
1220 * slave A-lists are chained to buffer A-lists.
1222 * See hammer_init_alist_config() below.
1226 * A-LIST - cluster recursion into a filesystem buffer
1229 buffer_alist_init(void *info, int32_t blk, int32_t radix)
1231 struct hammer_cluster *cluster = info;
1232 struct hammer_buffer *buffer;
1237 * Calculate the buffer number, initialize based on the buffer type.
1238 * The buffer has already been allocated so assert that it has been
1241 buf_no = blk / HAMMER_FSBUF_MAXBLKS;
1242 buffer = hammer_get_buffer(cluster, buf_no, 0, &error);
1244 hammer_put_buffer(buffer, 0);
1249 buffer_alist_destroy(void *info, int32_t blk, int32_t radix)
1255 buffer_alist_alloc_fwd(void *info, int32_t blk, int32_t radix,
1256 int32_t count, int32_t atblk, int32_t *fullp)
1258 struct hammer_cluster *cluster = info;
1259 struct hammer_buffer *buffer;
1264 buf_no = blk / HAMMER_FSBUF_MAXBLKS;
1265 buffer = hammer_get_buffer(cluster, buf_no, 0, &error);
1267 KKASSERT(buffer->ondisk->head.buf_type != 0);
1269 r = hammer_alist_alloc_fwd(&buffer->alist, count, atblk - blk);
1270 if (r != HAMMER_ALIST_BLOCK_NONE)
1272 *fullp = hammer_alist_isfull(&buffer->alist);
1273 hammer_put_buffer(buffer, 0);
1275 r = HAMMER_ALIST_BLOCK_NONE;
1281 buffer_alist_alloc_rev(void *info, int32_t blk, int32_t radix,
1282 int32_t count, int32_t atblk, int32_t *fullp)
1284 struct hammer_cluster *cluster = info;
1285 struct hammer_buffer *buffer;
1290 buf_no = blk / HAMMER_FSBUF_MAXBLKS;
1291 buffer = hammer_get_buffer(cluster, buf_no, 0, &error);
1293 KKASSERT(buffer->ondisk->head.buf_type != 0);
1295 r = hammer_alist_alloc_rev(&buffer->alist, count, atblk - blk);
1296 if (r != HAMMER_ALIST_BLOCK_NONE)
1298 *fullp = hammer_alist_isfull(&buffer->alist);
1299 hammer_put_buffer(buffer, 0);
1301 r = HAMMER_ALIST_BLOCK_NONE;
1308 buffer_alist_free(void *info, int32_t blk, int32_t radix,
1309 int32_t base_blk, int32_t count, int32_t *emptyp)
1311 struct hammer_cluster *cluster = info;
1312 struct hammer_buffer *buffer;
1316 buf_no = blk / HAMMER_FSBUF_MAXBLKS;
1317 buffer = hammer_get_buffer(cluster, buf_no, 0, &error);
1319 KKASSERT(buffer->ondisk->head.buf_type != 0);
1320 hammer_alist_free(&buffer->alist, base_blk, count);
1321 *emptyp = hammer_alist_isempty(&buffer->alist);
1322 hammer_put_buffer(buffer, 0);
1329 buffer_alist_print(void *info, int32_t blk, int32_t radix, int tab)
1334 * A-LIST - super-cluster recursion into a cluster and cluster recursion
1335 * into a filesystem buffer. A-List's are mostly self-contained entities,
1336 * but callbacks must be installed to recurse from one A-List to another.
1338 * Implementing these callbacks allows us to operate a multi-layered A-List
1339 * as a single entity.
1342 super_alist_init(void *info, int32_t blk, int32_t radix)
1344 struct hammer_volume *volume = info;
1345 struct hammer_supercl *supercl;
1350 * Calculate the super-cluster number containing the cluster (blk)
1351 * and obtain the super-cluster buffer.
1353 scl_no = blk / HAMMER_SCL_MAXCLUSTERS;
1354 supercl = hammer_get_supercl(volume, scl_no, &error, 1);
1356 hammer_put_supercl(supercl, 0);
1361 super_alist_destroy(void *info, int32_t blk, int32_t radix)
1367 super_alist_alloc_fwd(void *info, int32_t blk, int32_t radix,
1368 int32_t count, int32_t atblk, int32_t *fullp)
1370 struct hammer_volume *volume = info;
1371 struct hammer_supercl *supercl;
1376 scl_no = blk / HAMMER_SCL_MAXCLUSTERS;
1377 supercl = hammer_get_supercl(volume, scl_no, &error, 1);
1379 r = hammer_alist_alloc_fwd(&supercl->alist, count, atblk - blk);
1380 if (r != HAMMER_ALIST_BLOCK_NONE)
1382 *fullp = hammer_alist_isfull(&supercl->alist);
1383 hammer_put_supercl(supercl, 0);
1385 r = HAMMER_ALIST_BLOCK_NONE;
1392 super_alist_alloc_rev(void *info, int32_t blk, int32_t radix,
1393 int32_t count, int32_t atblk, int32_t *fullp)
1395 struct hammer_volume *volume = info;
1396 struct hammer_supercl *supercl;
1401 scl_no = blk / HAMMER_SCL_MAXCLUSTERS;
1402 supercl = hammer_get_supercl(volume, scl_no, &error, 1);
1404 r = hammer_alist_alloc_rev(&supercl->alist, count, atblk - blk);
1405 if (r != HAMMER_ALIST_BLOCK_NONE)
1407 *fullp = hammer_alist_isfull(&supercl->alist);
1408 hammer_put_supercl(supercl, 0);
1410 r = HAMMER_ALIST_BLOCK_NONE;
1417 super_alist_free(void *info, int32_t blk, int32_t radix,
1418 int32_t base_blk, int32_t count, int32_t *emptyp)
1420 struct hammer_volume *volume = info;
1421 struct hammer_supercl *supercl;
1425 scl_no = blk / HAMMER_SCL_MAXCLUSTERS;
1426 supercl = hammer_get_supercl(volume, scl_no, &error, 1);
1428 hammer_alist_free(&supercl->alist, base_blk, count);
1429 *emptyp = hammer_alist_isempty(&supercl->alist);
1430 hammer_put_supercl(supercl, 0);
1437 super_alist_print(void *info, int32_t blk, int32_t radix, int tab)
1442 hammer_init_alist_config(void)
1444 hammer_alist_config_t config;
1446 hammer_alist_template(&Buf_alist_config, HAMMER_FSBUF_MAXBLKS,
1447 1, HAMMER_FSBUF_METAELMS);
1448 hammer_alist_template(&Vol_normal_alist_config, HAMMER_VOL_MAXCLUSTERS,
1449 1, HAMMER_VOL_METAELMS_1LYR);
1450 hammer_alist_template(&Vol_super_alist_config,
1451 HAMMER_VOL_MAXSUPERCLUSTERS,
1452 HAMMER_SCL_MAXCLUSTERS, HAMMER_VOL_METAELMS_2LYR);
1453 hammer_alist_template(&Supercl_alist_config, HAMMER_VOL_MAXCLUSTERS,
1454 1, HAMMER_SUPERCL_METAELMS);
1455 hammer_alist_template(&Clu_master_alist_config, HAMMER_CLU_MAXBUFFERS,
1456 1, HAMMER_CLU_MASTER_METAELMS);
1457 hammer_alist_template(&Clu_slave_alist_config, HAMMER_CLU_MAXBUFFERS,
1458 HAMMER_FSBUF_MAXBLKS, HAMMER_CLU_SLAVE_METAELMS);
1460 config = &Vol_super_alist_config;
1461 config->bl_radix_init = super_alist_init;
1462 config->bl_radix_destroy = super_alist_destroy;
1463 config->bl_radix_alloc_fwd = super_alist_alloc_fwd;
1464 config->bl_radix_alloc_rev = super_alist_alloc_rev;
1465 config->bl_radix_free = super_alist_free;
1466 config->bl_radix_print = super_alist_print;
1468 config = &Clu_slave_alist_config;
1469 config->bl_radix_init = buffer_alist_init;
1470 config->bl_radix_destroy = buffer_alist_destroy;
1471 config->bl_radix_alloc_fwd = buffer_alist_alloc_fwd;
1472 config->bl_radix_alloc_rev = buffer_alist_alloc_rev;
1473 config->bl_radix_free = buffer_alist_free;
1474 config->bl_radix_print = buffer_alist_print;