1 /* 2 * Copyright (c) 2007 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: 10 * 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. 20 * 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. 33 * 34 * $DragonFly: src/sbin/hammer/ondisk.c,v 1.5 2007/12/14 08:05:37 dillon Exp $ 35 */ 36 37 #include "newfs_hammer.h" 38 39 static void initbuffer(hammer_alist_t live, hammer_fsbuf_head_t head, 40 u_int64_t type); 41 static void alloc_new_buffer(struct cluster_info *cluster, hammer_alist_t live, 42 u_int64_t type, int32_t nelements); 43 #if 0 44 static void readhammerbuf(struct volume_info *vol, void *data, 45 int64_t offset); 46 #endif 47 static void writehammerbuf(struct volume_info *vol, const void *data, 48 int64_t offset); 49 50 /* 51 * Lookup the requested information structure and related on-disk buffer. 52 * Except for getvolume(), these functions will create and initialize any 53 * missing info structures. 54 */ 55 struct volume_info * 56 get_volume(int32_t vol_no) 57 { 58 struct volume_info *vol; 59 struct hammer_volume_ondisk *ondisk; 60 61 for (vol = VolBase; vol; vol = vol->next) { 62 if (vol->vol_no == vol_no) 63 break; 64 } 65 if (vol && vol->ondisk == NULL) { 66 vol->ondisk = ondisk = malloc(HAMMER_BUFSIZE); 67 bzero(ondisk, HAMMER_BUFSIZE); 68 if (UsingSuperClusters) { 69 vol->clu_alist.config = &Vol_super_alist_config; 70 vol->clu_alist.meta = ondisk->vol_almeta.super; 71 vol->clu_alist.info = vol; 72 hammer_alist_init(&vol->clu_alist); 73 } else { 74 vol->clu_alist.config = &Vol_normal_alist_config; 75 vol->clu_alist.meta = ondisk->vol_almeta.normal; 76 hammer_alist_init(&vol->clu_alist); 77 } 78 vol->buf_alist.config = &Buf_alist_config; 79 vol->buf_alist.meta = ondisk->head.buf_almeta; 80 initbuffer(&vol->buf_alist, &ondisk->head, HAMMER_FSBUF_VOLUME); 81 } 82 return(vol); 83 } 84 85 struct supercl_info * 86 get_supercl(struct volume_info *vol, int32_t scl_no) 87 { 88 struct hammer_supercl_ondisk *ondisk; 89 struct supercl_info *scl; 90 int32_t scl_group; 91 int64_t scl_group_size; 92 93 assert(UsingSuperClusters); 94 95 for (scl = vol->supercl_base; scl; scl = scl->next) { 96 if (scl->scl_no == scl_no) 97 break; 98 } 99 if (scl == NULL) { 100 /* 101 * Allocate the scl 102 */ 103 scl = malloc(sizeof(*scl)); 104 bzero(scl, sizeof(*scl)); 105 scl->scl_no = scl_no; 106 scl->next = vol->supercl_base; 107 scl->volume = vol; 108 vol->supercl_base = scl; 109 110 /* 111 * Calculate the super-cluster's offset in the volume. 112 * 113 * The arrangement is [scl * N][N * 32768 clusters], repeat. 114 * N is typically 16. 115 */ 116 scl_group = scl_no / HAMMER_VOL_SUPERCLUSTER_GROUP; 117 scl_group_size = ((int64_t)HAMMER_BUFSIZE * 118 HAMMER_VOL_SUPERCLUSTER_GROUP) + 119 ((int64_t)HAMMER_VOL_SUPERCLUSTER_GROUP * 120 ClusterSize * HAMMER_SCL_MAXCLUSTERS); 121 scl->scl_offset = vol->ondisk->vol_clo_beg + 122 scl_group * scl_group_size + 123 (scl_no % HAMMER_VOL_SUPERCLUSTER_GROUP) * 124 HAMMER_BUFSIZE; 125 } 126 if (scl->ondisk == NULL) { 127 scl->ondisk = ondisk = malloc(HAMMER_BUFSIZE); 128 bzero(ondisk, HAMMER_BUFSIZE); 129 scl->clu_alist.config = &Supercl_alist_config; 130 scl->clu_alist.meta = ondisk->scl_meta; 131 hammer_alist_init(&scl->clu_alist); 132 scl->buf_alist.config = &Buf_alist_config; 133 scl->buf_alist.meta = ondisk->head.buf_almeta; 134 initbuffer(&scl->buf_alist, &ondisk->head, HAMMER_FSBUF_SUPERCL); 135 } 136 return(scl); 137 } 138 139 struct cluster_info * 140 get_cluster(struct volume_info *vol, int32_t clu_no) 141 { 142 struct hammer_cluster_ondisk *ondisk; 143 struct cluster_info *cl; 144 int32_t scl_group; 145 int64_t scl_group_size; 146 147 for (cl = vol->cluster_base; cl; cl = cl->next) { 148 if (cl->clu_no == clu_no) 149 break; 150 } 151 if (cl == NULL) { 152 /* 153 * Allocate the cluster 154 */ 155 cl = malloc(sizeof(*cl)); 156 bzero(cl, sizeof(*cl)); 157 cl->clu_no = clu_no; 158 cl->next = vol->cluster_base; 159 if (UsingSuperClusters) { 160 cl->supercl = get_supercl(vol, clu_no / HAMMER_SCL_MAXCLUSTERS); 161 } 162 cl->volume = vol; 163 vol->cluster_base = cl; 164 165 /* 166 * Calculate the cluster's offset in the volume 167 * 168 * The arrangement is [scl * N][N * 32768 clusters], repeat. 169 * N is typically 16. 170 * 171 * Note that the cluster offset calculation is slightly 172 * different from the supercluster offset calculation due 173 * to the way the grouping works. 174 */ 175 if (UsingSuperClusters) { 176 scl_group = clu_no / HAMMER_VOL_SUPERCLUSTER_GROUP / 177 HAMMER_SCL_MAXCLUSTERS; 178 scl_group_size = 179 ((int64_t)HAMMER_BUFSIZE * 180 HAMMER_VOL_SUPERCLUSTER_GROUP) + 181 ((int64_t)HAMMER_VOL_SUPERCLUSTER_GROUP * 182 ClusterSize * HAMMER_SCL_MAXCLUSTERS); 183 scl_group_size += HAMMER_VOL_SUPERCLUSTER_GROUP * 184 HAMMER_BUFSIZE; 185 cl->clu_offset = 186 vol->ondisk->vol_clo_beg + 187 scl_group * scl_group_size + 188 (HAMMER_BUFSIZE * HAMMER_VOL_SUPERCLUSTER_GROUP) + 189 ((int64_t)clu_no % ((int64_t)HAMMER_SCL_MAXCLUSTERS * HAMMER_VOL_SUPERCLUSTER_GROUP)) * 190 HAMMER_BUFSIZE; 191 } else { 192 cl->clu_offset = vol->ondisk->vol_clo_beg + 193 (int64_t)clu_no * ClusterSize; 194 } 195 } 196 if (cl->ondisk == NULL) { 197 cl->ondisk = ondisk = malloc(HAMMER_BUFSIZE); 198 bzero(ondisk, HAMMER_BUFSIZE); 199 cl->alist_master.config = &Clu_master_alist_config; 200 cl->alist_master.meta = ondisk->clu_master_meta; 201 hammer_alist_init(&cl->alist_master); 202 cl->alist_btree.config = &Clu_slave_alist_config; 203 cl->alist_btree.meta = ondisk->clu_btree_meta; 204 cl->alist_btree.info = cl; 205 hammer_alist_init(&cl->alist_btree); 206 cl->alist_record.config = &Clu_slave_alist_config; 207 cl->alist_record.meta = ondisk->clu_record_meta; 208 cl->alist_record.info = cl; 209 hammer_alist_init(&cl->alist_record); 210 cl->alist_mdata.config = &Clu_slave_alist_config; 211 cl->alist_mdata.meta = ondisk->clu_mdata_meta; 212 cl->alist_mdata.info = cl; 213 hammer_alist_init(&cl->alist_mdata); 214 } 215 return(cl); 216 } 217 218 struct buffer_info * 219 get_buffer(struct cluster_info *cl, int32_t buf_no, int64_t buf_type) 220 { 221 hammer_fsbuf_ondisk_t ondisk; 222 struct buffer_info *buf; 223 224 /* 225 * Find the buffer. Note that buffer 0 corresponds to the cluster 226 * header and should never be requested. 227 */ 228 assert(buf_no != 0); 229 for (buf = cl->buffer_base; buf; buf = buf->next) { 230 if (buf->buf_no == buf_no) 231 break; 232 } 233 if (buf == NULL) { 234 buf = malloc(sizeof(*buf)); 235 bzero(buf, sizeof(*buf)); 236 buf->buf_no = buf_no; 237 buf->buf_offset = cl->clu_offset + buf_no * HAMMER_BUFSIZE; 238 buf->cluster = cl; 239 buf->volume = cl->volume; 240 buf->next = cl->buffer_base; 241 cl->buffer_base = buf; 242 } 243 if (buf->ondisk == NULL) { 244 buf->ondisk = ondisk = malloc(HAMMER_BUFSIZE); 245 bzero(ondisk, HAMMER_BUFSIZE); 246 buf->alist.config = &Buf_alist_config; 247 buf->alist.meta = ondisk->head.buf_almeta; 248 initbuffer(&buf->alist, &ondisk->head, buf_type); 249 } 250 return(buf); 251 } 252 253 /* 254 * Allocate HAMMER elements - btree nodes, data storage, and record elements 255 */ 256 void * 257 alloc_btree_element(struct cluster_info *cluster, int32_t *offp) 258 { 259 struct buffer_info *buf; 260 hammer_alist_t live; 261 int32_t elm_no; 262 void *item; 263 264 live = &cluster->alist_btree; 265 elm_no = hammer_alist_alloc_fwd(live, 1, cluster->ondisk->idx_index); 266 if (elm_no == HAMMER_ALIST_BLOCK_NONE) 267 elm_no = hammer_alist_alloc_fwd(live, 1, 0); 268 if (elm_no == HAMMER_ALIST_BLOCK_NONE) { 269 alloc_new_buffer(cluster, live, 270 HAMMER_FSBUF_BTREE, HAMMER_BTREE_NODES); 271 ++cluster->ondisk->stat_idx_bufs; 272 ++cluster->volume->ondisk->vol_stat_idx_bufs; 273 ++cluster->volume->ondisk->vol0_stat_idx_bufs; 274 elm_no = hammer_alist_alloc(live, 1); 275 assert(elm_no != HAMMER_ALIST_BLOCK_NONE); 276 } 277 cluster->ondisk->idx_index = elm_no; 278 buf = get_buffer(cluster, elm_no / HAMMER_FSBUF_MAXBLKS, 0); 279 assert(buf->ondisk->head.buf_type != 0); 280 item = &buf->ondisk->btree.nodes[elm_no & HAMMER_FSBUF_BLKMASK]; 281 *offp = buf->buf_no * HAMMER_BUFSIZE + 282 ((char *)item - (char *)buf->ondisk); 283 return(item); 284 } 285 286 void * 287 alloc_data_element(struct cluster_info *cluster, int32_t bytes, int32_t *offp) 288 { 289 struct buffer_info *buf; 290 hammer_alist_t live; 291 int32_t elm_no; 292 int32_t nblks = (bytes + HAMMER_DATA_BLKMASK) & ~HAMMER_DATA_BLKMASK; 293 void *item; 294 295 /* 296 * Try to allocate a btree-node. If elm_no is HAMMER_ALIST_BLOCK_NONE 297 * and buf is non-NULL we have to initialize a new buffer's a-list. 298 */ 299 live = &cluster->alist_mdata; 300 elm_no = hammer_alist_alloc_fwd(live, nblks, cluster->ondisk->idx_data); 301 if (elm_no == HAMMER_ALIST_BLOCK_NONE) 302 elm_no = hammer_alist_alloc_fwd(live, 1, 0); 303 if (elm_no == HAMMER_ALIST_BLOCK_NONE) { 304 alloc_new_buffer(cluster, live, 305 HAMMER_FSBUF_DATA, HAMMER_DATA_NODES); 306 ++cluster->ondisk->stat_data_bufs; 307 ++cluster->volume->ondisk->vol_stat_data_bufs; 308 ++cluster->volume->ondisk->vol0_stat_data_bufs; 309 elm_no = hammer_alist_alloc(live, nblks); 310 assert(elm_no != HAMMER_ALIST_BLOCK_NONE); 311 } 312 cluster->ondisk->idx_index = elm_no; 313 buf = get_buffer(cluster, elm_no / HAMMER_FSBUF_MAXBLKS, 0); 314 assert(buf->ondisk->head.buf_type != 0); 315 item = &buf->ondisk->data.data[elm_no & HAMMER_FSBUF_BLKMASK]; 316 *offp = buf->buf_no * HAMMER_BUFSIZE + 317 ((char *)item - (char *)buf->ondisk); 318 return(item); 319 } 320 321 void * 322 alloc_record_element(struct cluster_info *cluster, int32_t *offp) 323 { 324 struct buffer_info *buf; 325 hammer_alist_t live; 326 int32_t elm_no; 327 void *item; 328 329 live = &cluster->alist_record; 330 elm_no = hammer_alist_alloc_rev(live, 1, cluster->ondisk->idx_record); 331 if (elm_no == HAMMER_ALIST_BLOCK_NONE) 332 elm_no = hammer_alist_alloc_rev(live, 1,HAMMER_ALIST_BLOCK_MAX); 333 if (elm_no == HAMMER_ALIST_BLOCK_NONE) { 334 alloc_new_buffer(cluster, live, 335 HAMMER_FSBUF_RECORDS, HAMMER_RECORD_NODES); 336 ++cluster->ondisk->stat_rec_bufs; 337 ++cluster->volume->ondisk->vol_stat_rec_bufs; 338 ++cluster->volume->ondisk->vol0_stat_rec_bufs; 339 elm_no = hammer_alist_alloc_rev(live, 1,HAMMER_ALIST_BLOCK_MAX); 340 assert(elm_no != HAMMER_ALIST_BLOCK_NONE); 341 } 342 cluster->ondisk->idx_record = elm_no; 343 buf = get_buffer(cluster, elm_no / HAMMER_FSBUF_MAXBLKS, 0); 344 assert(buf->ondisk->head.buf_type != 0); 345 item = &buf->ondisk->record.recs[elm_no & HAMMER_FSBUF_BLKMASK]; 346 *offp = buf->buf_no * HAMMER_BUFSIZE + 347 ((char *)item - (char *)buf->ondisk); 348 return(item); 349 } 350 351 static void 352 alloc_new_buffer(struct cluster_info *cluster, hammer_alist_t live, 353 u_int64_t type, int32_t nelements) 354 { 355 int32_t buf_no; 356 struct buffer_info *buf; 357 358 if (type == HAMMER_FSBUF_RECORDS) { 359 buf_no = hammer_alist_alloc_rev(&cluster->alist_master, 1, 360 HAMMER_ALIST_BLOCK_MAX); 361 } else { 362 buf_no = hammer_alist_alloc_fwd(&cluster->alist_master, 1, 363 0); 364 } 365 assert(buf_no != HAMMER_ALIST_BLOCK_NONE); 366 buf = get_buffer(cluster, buf_no, type); 367 hammer_alist_free(live, buf_no * HAMMER_FSBUF_MAXBLKS, nelements); 368 } 369 370 /* 371 * Flush various tracking structures to disk 372 */ 373 374 /* 375 * Flush various tracking structures to disk 376 */ 377 void 378 flush_all_volumes(void) 379 { 380 struct volume_info *vol; 381 382 for (vol = VolBase; vol; vol = vol->next) 383 flush_volume(vol); 384 } 385 386 void 387 flush_volume(struct volume_info *vol) 388 { 389 struct supercl_info *supercl; 390 struct cluster_info *cl; 391 392 for (supercl = vol->supercl_base; supercl; supercl = supercl->next) 393 flush_supercl(supercl); 394 for (cl = vol->cluster_base; cl; cl = cl->next) 395 flush_cluster(cl); 396 writehammerbuf(vol, vol->ondisk, 0); 397 } 398 399 void 400 flush_supercl(struct supercl_info *supercl) 401 { 402 int64_t supercl_offset; 403 404 supercl_offset = supercl->scl_offset; 405 writehammerbuf(supercl->volume, supercl->ondisk, supercl_offset); 406 } 407 408 void 409 flush_cluster(struct cluster_info *cl) 410 { 411 struct buffer_info *buf; 412 int64_t cluster_offset; 413 414 for (buf = cl->buffer_base; buf; buf = buf->next) 415 flush_buffer(buf); 416 cluster_offset = cl->clu_offset; 417 writehammerbuf(cl->volume, cl->ondisk, cluster_offset); 418 } 419 420 void 421 flush_buffer(struct buffer_info *buf) 422 { 423 writehammerbuf(buf->volume, buf->ondisk, buf->buf_offset); 424 } 425 426 /* 427 * Generic buffer initialization 428 */ 429 static void 430 initbuffer(hammer_alist_t live, hammer_fsbuf_head_t head, u_int64_t type) 431 { 432 head->buf_type = type; 433 hammer_alist_init(live); 434 } 435 436 #if 0 437 /* 438 * Core I/O operations 439 */ 440 static void 441 readhammerbuf(struct volume_info *vol, void *data, int64_t offset) 442 { 443 ssize_t n; 444 445 n = pread(vol->fd, data, HAMMER_BUFSIZE, offset); 446 if (n != HAMMER_BUFSIZE) 447 err(1, "Read volume %d (%s)", vol->vol_no, vol->name); 448 } 449 450 #endif 451 452 static void 453 writehammerbuf(struct volume_info *vol, const void *data, int64_t offset) 454 { 455 ssize_t n; 456 457 n = pwrite(vol->fd, data, HAMMER_BUFSIZE, offset); 458 if (n != HAMMER_BUFSIZE) 459 err(1, "Write volume %d (%s)", vol->vol_no, vol->name); 460 } 461 462