HAMMER 40D/Many: Inode/link-count sequencer cleanup pass.
[dragonfly.git] / sys / vfs / hammer / hammer_freemap.c
blobf15b3521a9c80d62c9f6f0c423660584dbb4a192
1 /*
2 * Copyright (c) 2008 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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
16 * distribution.
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
32 * SUCH DAMAGE.
34 * $DragonFly: src/sys/vfs/hammer/hammer_freemap.c,v 1.8 2008/05/03 05:28:55 dillon Exp $
38 * HAMMER freemap - bigblock allocator. The freemap is a 2-layer blockmap
39 * with one layer2 entry for each big-block in the filesystem. Big blocks
40 * are 8MB blocks.
42 * Our allocator is fairly straightforward, we just iterate through available
43 * blocks looking for a free one. We shortcut the iteration based on
44 * layer1 availability.
47 #include "hammer.h"
49 hammer_off_t
50 hammer_freemap_alloc(hammer_transaction_t trans, hammer_off_t owner,
51 int *errorp)
53 hammer_volume_ondisk_t ondisk;
54 hammer_off_t layer1_offset;
55 hammer_off_t layer2_offset;
56 hammer_off_t result_offset;
57 hammer_blockmap_t blockmap;
58 hammer_buffer_t buffer1 = NULL;
59 hammer_buffer_t buffer2 = NULL;
60 struct hammer_blockmap_layer1 *layer1;
61 struct hammer_blockmap_layer2 *layer2;
62 int vol_no;
63 int loops = 0;
65 *errorp = 0;
66 ondisk = trans->rootvol->ondisk;
68 blockmap = &trans->hmp->blockmap[HAMMER_ZONE_FREEMAP_INDEX];
69 result_offset = blockmap->next_offset;
70 vol_no = HAMMER_VOL_DECODE(result_offset);
71 for (;;) {
72 layer1_offset = blockmap->phys_offset +
73 HAMMER_BLOCKMAP_LAYER1_OFFSET(result_offset);
75 layer1 = hammer_bread(trans->hmp, layer1_offset, errorp, &buffer1);
76 if (layer1->phys_offset == HAMMER_BLOCKMAP_UNAVAIL) {
78 * End-of-volume, try next volume.
80 new_volume:
81 ++vol_no;
82 if (vol_no >= trans->hmp->nvolumes)
83 vol_no = 0;
84 result_offset = HAMMER_ENCODE_RAW_BUFFER(vol_no, 0);
85 if (vol_no == 0 && ++loops == 2) {
86 *errorp = ENOSPC;
87 result_offset = 0;
88 goto done;
90 } else {
91 layer2_offset = layer1->phys_offset +
92 HAMMER_BLOCKMAP_LAYER2_OFFSET(result_offset);
93 layer2 = hammer_bread(trans->hmp, layer2_offset, errorp,
94 &buffer2);
95 if (layer2->u.owner == HAMMER_BLOCKMAP_FREE) {
96 hammer_modify_buffer(trans, buffer2,
97 layer2, sizeof(*layer2));
98 layer2->u.owner = owner &
99 ~HAMMER_LARGEBLOCK_MASK64;
100 hammer_modify_buffer_done(buffer2);
101 hammer_modify_buffer(trans, buffer1,
102 layer1, sizeof(*layer1));
103 --layer1->blocks_free;
104 hammer_modify_buffer_done(buffer1);
105 hammer_modify_volume(trans, trans->rootvol,
106 &ondisk->vol0_stat_freebigblocks,
107 sizeof(ondisk->vol0_stat_freebigblocks));
108 --ondisk->vol0_stat_freebigblocks;
109 hammer_modify_volume_done(trans->rootvol);
110 break;
112 if (layer1->blocks_free == 0 ||
113 layer2->u.owner == HAMMER_BLOCKMAP_UNAVAIL) {
115 * layer2 has no free blocks remaining,
116 * skip to the next layer.
118 result_offset = (result_offset + HAMMER_BLOCKMAP_LAYER2_MASK) & ~HAMMER_BLOCKMAP_LAYER2_MASK;
119 if (HAMMER_VOL_DECODE(result_offset) != vol_no)
120 goto new_volume;
121 } else {
122 result_offset += HAMMER_LARGEBLOCK_SIZE;
123 if (HAMMER_VOL_DECODE(result_offset) != vol_no)
124 goto new_volume;
128 hammer_modify_volume(trans, trans->rootvol, NULL, 0);
129 blockmap->next_offset = result_offset + HAMMER_LARGEBLOCK_SIZE;
130 hammer_modify_volume_done(trans->rootvol);
131 done:
132 if (buffer1)
133 hammer_rel_buffer(buffer1, 0);
134 if (buffer2)
135 hammer_rel_buffer(buffer2, 0);
136 return(result_offset);
139 void
140 hammer_freemap_free(hammer_transaction_t trans, hammer_off_t phys_offset,
141 hammer_off_t owner, int *errorp)
143 hammer_volume_ondisk_t ondisk;
144 hammer_off_t layer1_offset;
145 hammer_off_t layer2_offset;
146 hammer_blockmap_t blockmap;
147 hammer_buffer_t buffer1 = NULL;
148 hammer_buffer_t buffer2 = NULL;
149 struct hammer_blockmap_layer1 *layer1;
150 struct hammer_blockmap_layer2 *layer2;
152 KKASSERT((phys_offset & HAMMER_LARGEBLOCK_MASK64) == 0);
154 hammer_uncache_buffer(trans->hmp, phys_offset);
155 *errorp = 0;
156 ondisk = trans->rootvol->ondisk;
158 blockmap = &trans->hmp->blockmap[HAMMER_ZONE_FREEMAP_INDEX];
159 layer1_offset = blockmap->phys_offset +
160 HAMMER_BLOCKMAP_LAYER1_OFFSET(phys_offset);
161 layer1 = hammer_bread(trans->hmp, layer1_offset, errorp, &buffer1);
163 KKASSERT(layer1->phys_offset != HAMMER_BLOCKMAP_UNAVAIL);
165 layer2_offset = layer1->phys_offset +
166 HAMMER_BLOCKMAP_LAYER2_OFFSET(phys_offset);
167 layer2 = hammer_bread(trans->hmp, layer2_offset, errorp, &buffer2);
169 KKASSERT(layer2->u.owner == (owner & ~HAMMER_LARGEBLOCK_MASK64));
170 hammer_modify_buffer(trans, buffer1, layer1, sizeof(*layer1));
171 ++layer1->blocks_free;
172 hammer_modify_buffer_done(buffer1);
173 hammer_modify_buffer(trans, buffer2, layer2, sizeof(*layer2));
174 layer2->u.owner = HAMMER_BLOCKMAP_FREE;
175 hammer_modify_buffer_done(buffer2);
177 hammer_modify_volume(trans, trans->rootvol,
178 &ondisk->vol0_stat_freebigblocks,
179 sizeof(ondisk->vol0_stat_freebigblocks));
180 ++ondisk->vol0_stat_freebigblocks;
181 hammer_modify_volume_done(trans->rootvol);
183 if (buffer1)
184 hammer_rel_buffer(buffer1, 0);
185 if (buffer2)
186 hammer_rel_buffer(buffer2, 0);