1/* 2 * Copyright (c) 2010 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of Apple Inc. ("Apple") nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * Portions of this software have been released under the following terms: 31 * 32 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC. 33 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY 34 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION 35 * 36 * To anyone who acknowledges that this file is provided "AS IS" 37 * without any express or implied warranty: 38 * permission to use, copy, modify, and distribute this file for any 39 * purpose is hereby granted without fee, provided that the above 40 * copyright notices and this notice appears in all source code copies, 41 * and that none of the names of Open Software Foundation, Inc., Hewlett- 42 * Packard Company or Digital Equipment Corporation be used 43 * in advertising or publicity pertaining to distribution of the software 44 * without specific, written prior permission. Neither Open Software 45 * Foundation, Inc., Hewlett-Packard Company nor Digital 46 * Equipment Corporation makes any representations about the suitability 47 * of this software for any purpose. 48 * 49 * Copyright (c) 2007, Novell, Inc. All rights reserved. 50 * Redistribution and use in source and binary forms, with or without 51 * modification, are permitted provided that the following conditions 52 * are met: 53 * 54 * 1. Redistributions of source code must retain the above copyright 55 * notice, this list of conditions and the following disclaimer. 56 * 2. Redistributions in binary form must reproduce the above copyright 57 * notice, this list of conditions and the following disclaimer in the 58 * documentation and/or other materials provided with the distribution. 59 * 3. Neither the name of Novell Inc. nor the names of its contributors 60 * may be used to endorse or promote products derived from this 61 * this software without specific prior written permission. 62 * 63 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 64 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 65 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 66 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY 67 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 68 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 69 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 70 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 71 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 72 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 73 * 74 * @APPLE_LICENSE_HEADER_END@ 75 */ 76 77/* 78** 79** NAME: 80** 81** dsm_p.h 82** 83** FACILITY: 84** 85** Data Storage Manager (DSM) 86** 87** ABSTRACT: 88** 89** Data storage manager private header file. 90** 91** 92*/ 93 94#include <dce/dce.h> 95#define DCETHREAD_CHECKED 96#define DCETHREAD_USE_THROW 97#include <dce/dcethread.h> 98#include <dsm.h> 99#include <assert.h> 100#include <stddef.h> 101#include <errno.h> 102#include <sys/file.h> 103 104/* 105 * lseek direction macros 106 */ 107#ifndef L_SET 108#define L_SET 0 /* absolute offset */ 109#endif 110 111#ifndef L_INCR 112#define L_INCR 1 /* relative to current offset */ 113#endif 114 115#ifndef L_XTND 116#define L_XTND 2 /* relative to end of file */ 117#endif 118 119#define status_ok error_status_ok 120#define boolean ndr_boolean 121 122/* Records in the data store file are laid out contiguously. Each record begins with 123 a preheader used by DSM (not seen by user). Each record is padded to a length that 124 ensures clean alignment (at least 8-byte); the preheader is of such a length that 125 the user data is also cleanly aligned after the preheader. 126 127 We want to arrange that our header fits within a page, as well as a reasonable chunk 128 of the beginning of the user data, so the client can have atomic header writes. 129*/ 130 131#if defined (vms) 132# define PAGE_SIZE 512 /* length of system page */ 133#else 134#if defined(__linux__) 135# define PAGE_SIZE 4096 136#elif !defined(PAGE_SIZE) 137# define PAGE_SIZE 1024 /* length of system page */ 138#endif 139#endif 140 141#define INFOSZ 256 /* space reserved for client header info */ 142#define PREHEADER (sizeof(block_t) - sizeof(double)) /* length of preheader */ 143#define UNIT 64 /* 1st UNIT of each block should fit within a page */ 144#define USER_HDR (UNIT-PREHEADER) /* leaving this for a user header */ 145#define MINBLOCK (PREHEADER+8) /* we'll deal with blocks as small as this */ 146#define GROW_PAGES 5 /* growth unit */ 147#define HDR_COOKIE 0xA5 /* magic cookie in preheaders */ 148#define DSM_COOKIE 0xADEADBEEU /* magic cookie in dsh */ 149#define MAX_PATH 1024 /* maximum pathname length */ 150 151#define MAGIC_MARKER (unsigned32)dsm_magic_marker /* "magic", invalid marker */ 152 153/* rounding/modulus operations on powers of 2 */ 154#define ROUND_UP(n,po2) (((n)+((po2)-1))&(~((po2)-1))) /* round n up to next po2 */ 155#define ROUND_DOWN(n,po2) ((n)&(~((po2)-1))) /* round down to prev po2 */ 156#define MOD(n,po2) ((n)&((po2)-1)) /* n mod po2 */ 157 158#ifndef MAX 159#define MAX(a,b) ((a>b)?a:b) 160#endif 161#ifndef MIN 162#define MIN(a,b) ((a<b)?a:b) 163#endif 164 165#define NEW(type) (type *)malloc(sizeof(type)) 166 167#define ustrlcpy(a,b,c) strlcpy((char *)(a),(char *)(b),c) 168#define ustrlcat(a,b,c) strlcat((char *)(a),(char *)(b),c) 169#define ustrlen(a) strlen((char *)(a)) 170#define ustrcmp(a,b) strcmp((char *)(a),(char *)(b)) 171 172#define BAD_ST ((*st) != status_ok) 173#define GOOD_ST ((*st) == status_ok) 174#define CLEAR_ST ((*st) = status_ok) 175 176/* Cleanup handling. Earlier model was based on Apollo PFM, no current 177 contender fits that model (combining exception handling and status codes) 178 so here's a placeholder using strictly local gotos (pfm is based on 179 nonlocal gotos aka longjmp). Assumes error_status_t *st in scope. 180 181 CLEANUP { 182 stuff 183 return; 184 } 185 ... 186 if (bad_thing) SIGNAL(error_status); 187*/ 188 189#define CLEANUP if (0) CH_LABEL: 190#define SIGNAL(s) { (*st) = (s); goto CH_LABEL; } 191#define PROP_BAD_ST if (BAD_ST) SIGNAL(*st) /* propagate (via signal) bad status */ 192 193#define private static 194#define public 195 196#if defined(_HPUX) 197/* HP-UX hack around system-defined page_t */ 198#define page_t my_page_t 199#endif 200 201typedef struct page_t { /* generic page */ 202 unsigned char page_contents[PAGE_SIZE]; 203} page_t; 204 205/* Strong assumptions are made about the size and alignments of this 206 structure! The important thing is that it the 'data' field be 207 naturally aligned for all potential user data (8-byte alignment), 208 and the preheader should occupy the PREHEADER bytes just before 209 the user data. It currently looks like: (16 bytes) 210 211 +--------+--------+--------+--------+ \ 212 | space for link ptr | | 213 +--------+--------+--------+--------+ | 214 | size of user data | | 215 +--------+--------+--------+--------+ > preheader (16 bytes) 216 | offset in file of preheader | | 217 +--------+--------+--------+--------+ | 218 | FREE | cookie | (unused) | | 219 +--------+--------+--------+--------+ / 220 | user data... 221 +--------+ 222*/ 223 224typedef struct block_t { /* block preheader */ 225 struct block_t *link; /* link to next block on (free) list [meaningless in file] */ 226 unsigned long size; /* size of user data */ 227 unsigned long loc; /* location (offset) of preheader in file */ 228 boolean isfree; /* true iff free */ 229 unsigned char cookie; /* magic number basic identification */ 230 unsigned char unused[2]; /* preheader ends here */ 231 double data; /* user data begins here -- double to align */ 232} block_t; 233 234typedef struct file_hdr_t { /* first page of file contains global info */ 235 long version; /* file format version */ 236 long pages; /* number of initialized data pages */ 237 long pad1[20]; /* reserve for DSM header expansion */ 238 unsigned char info[INFOSZ]; /* space for client info */ 239 page_t padding; /* pad out past page boundary */ 240} file_hdr_t; 241 242/* Upon opening a data store file we allocate a chunk of memory big 243 enough to hold the whole thing and read it in. As the file grows 244 we allocate smaller chunks corresponding to new pieces of the 245 file. In memory most access will be via lists, but for sequential 246 traversal we have to find all chunks (also for freeing upon close) 247 so we keep a list of chunks in order in the file. 248*/ 249typedef struct file_map_t { /* file chunk descriptor */ 250 struct file_map_t *link; /* next in list */ 251 block_t *ptr; /* pointer to first block in chunk */ 252 unsigned long loc; /* location in file (should be on page boundary) */ 253 unsigned long size; /* bytes total (should be in page multiple) */ 254} file_map_t; 255 256typedef struct cache_t { /* dsm_read cache element */ 257 dsm_marker_t loc; /* location in file */ 258 block_t *p; /* block in memory */ 259} cache_t; 260 261typedef struct dsm_db_t { /* dsm handle info (what dsm_handle_t really points to) */ 262 block_t *freelist; /* free block list */ 263 int fd; /* the file descriptor */ 264 char *fname; /* pointer to malloc'd copy of filename */ 265 file_map_t *map; /* the file map (head of list) */ 266 long pages; /* initialized pages (from file header) */ 267 long cookie; /* magic cookie for detecting bogus dsh's */ 268 int pending; /* # blocks allocated but not written */ 269 cache_t cache; /* dsm_read cache */ 270 boolean coalesced; /* true once coalesced */ 271} dsm_db_t; 272 273typedef struct dsm_db_t * dsm_handle; /* internal version of opaque handle */ 274 275/* private function prototypes; copied here to force type checking and loosen 276 sequence. 277*/ 278 279#ifdef _I_AM_DSM_C_ 280private block_t * get_free_block (dsm_handle,unsigned long); 281private block_t * grow_file (dsm_handle,unsigned long, error_status_t *); 282private void write_header (dsm_handle,block_t *, error_status_t *); 283private void write_block (dsm_handle,block_t *,unsigned long, error_status_t *); 284private void update_file_header (dsm_handle, error_status_t *); 285private int create_file (unsigned char *); 286private void make_free (dsm_handle,block_t *, error_status_t *); 287private void free_block (dsm_handle,block_t *); 288private void free_map (file_map_t *); 289private void coalesce (dsm_handle, error_status_t *); 290private void build_freelist (dsm_handle); 291private block_t * get_next_block (dsm_handle,block_t *); 292private block_t * block_from_ptr (void *, error_status_t *); 293private block_t * get_earlier_block (dsm_handle,dsm_marker_t); 294private void cache_clear (dsm_handle); 295private void cache_add (dsm_handle,block_t *,dsm_marker_t); 296private block_t * cache_lookup (dsm_handle,dsm_marker_t); 297#endif 298public void dsm__lock_file (int, error_status_t *); 299public int dsm__flush_file (int); 300