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