1#include <uuid/uuid.h> 2 3/* 4 * Files. 5 */ 6#define BC_ROOT_PLAYLIST "/var/db/BootCache.playlist" 7#define BC_ROOT_EXTRA_LOGICAL_PLAYLIST "/var/db/BootCaches/RootExtra.logical_playlist" 8#define BC_LOGIN_EXTRA_LOGICAL_PLAYLIST "/var/db/BootCaches/LoginExtra.logical_playlist" 9#define BC_ROOT_LOGICAL_PLAYLIST "/var/db/BootCaches/Root.logical_playlist" 10#define BC_LOGIN_LOGICAL_PLAYLIST "/var/db/BootCaches/Login.logical_playlist" 11#define BC_BOOT_BACKINGFILE "/var/db/BootCache.data" 12#define BC_BOOT_FLAGFILE "/var/db/BootCache.flag" 13#define BC_BOOT_STATFILE "/tmp/BootCache.statistics" 14#define BC_BOOT_HISTFILE "/tmp/BootCache.history" 15#define BC_BOOT_LOGFILE "/tmp/BootCache.log" 16#define BC_CONTROL_TOOL "/usr/sbin/BootCacheControl" 17#define BC_KEXTUNLOAD "/sbin/kextunload" 18#define BC_BUNDLE_ID "com.apple.BootCache" 19 20/* 21 * Files we read in during every boot. 22 */ 23#if defined __x86_64__ 24#define BC_DYLD_SHARED_CACHE "/var/db/dyld/dyld_shared_cache_x86_64" 25#define BC_DYLD_SHARED_CACHE_32 "/var/db/dyld/dyld_shared_cache_i386" 26#elif defined __i386__ 27#define BC_DYLD_SHARED_CACHE "/var/db/dyld/dyld_shared_cache_i386" 28#else 29#warning "Unkown architecture" 30#undef BC_DYLD_SHARED_CACHE 31#endif 32 33/* 34 * If defined, entries/extents are sorted by their location on disk 35 * (rather than chronologically or some other sorting). 36 */ 37#define BOOTCACHE_ENTRIES_SORTED_BY_DISK_OFFSET 38 39/* 40 * Command stucture, passed via sysctl. 41 */ 42struct BC_command { 43 /* magic number identifies the structure */ 44 int bc_magic; 45#define BC_MAGIC_0 0x10102021 /* old version with DEV_BSIZE blocks */ 46#define BC_MAGIC_1 0x10102021 /* all disk addresses in bytes */ 47#define BC_MAGIC_2 0x10102021 /* added flags field to playlist entry */ 48#define BC_MAGIC_3 0x10102022 /* major restructure, added mounts */ 49#define BC_MAGIC 0x10102023 /* add pid/shared flag to history */ 50 51 /* opcode determines function of this command */ 52 int bc_opcode; 53#define BC_OP_START 0x01 54#define BC_OP_STOP 0x02 55#define BC_OP_HISTORY 0x03 56#define BC_OP_STATS 0x04 57#define BC_OP_TAG 0x05 58#define BC_OP_JETTISON 0x06 59#define BC_OP_MOUNT 0x07 60#define BC_OP_TEST 0x08 61 62 /* user-space data buffers, use varies with opcode */ 63 unsigned int bc_data1_size; 64 unsigned int bc_data2_size; 65 u_int64_t bc_data1; 66 u_int64_t bc_data2; 67}; 68 69#define BC_SYSCTL "kern.BootCache" 70 71/* 72 * BC_OP_START - start the cache engine with an optional playlist. 73 * 74 * If bc_data1 is not NULL, it points to bc_data1_size bytes of 75 * BC_playlist_mount structures. 76 * 77 * If bc_data2 is not NULL, it points to bc_data2_size bytes of 78 * BC_playlist_entry structures. 79 */ 80 81/* 82 * On-disk playlist header, also used in the preload case. 83 */ 84struct BC_playlist_header { 85 int ph_magic; 86#define PH_MAGIC_0 0xa1b2c3d4 /* old format with no blocksize */ 87#define PH_MAGIC_1 0xa1b2c3d5 /* blocksize, offsets in bytes */ 88#define PH_MAGIC_2 0xa1b2c3d6 /* added flags field */ 89#define PH_MAGIC_3 0xa1b2c3d7 /* added non-root mounts */ 90#define PH_MAGIC 0xa1b2c3d8 /* added low-priority extents */ 91 int ph_nmounts; 92 int ph_nentries; 93}; 94 95/* 96 * Playlist mounts represent mount points to be cached. 97 */ 98struct BC_playlist_mount { 99 uuid_t pm_uuid; /* The UUID of the mount */ 100 int pm_nentries; /* The number of playlist entries that refer to this mount */ 101}; 102 103/* 104 * Playlist entries represent regions of the mount points to be cached. 105 */ 106struct BC_playlist_entry { 107 u_int64_t pe_offset; /* block address */ 108 u_int64_t pe_length; /* size */ 109 u_int16_t pe_batch; /* batch number */ 110 u_int16_t pe_flags; /* flags */ 111#define BC_PE_LOWPRIORITY 0x1 112#define BC_PE_SHARED 0x2 113 u_int32_t pe_mount_idx; /* index of mount in mount array */ 114}; 115 116/* number of entries we copyin at a time */ 117#define BC_PLC_CHUNK 512 118 119/* sanity check for the upper bound on number of entries and batches */ 120#define BC_MAXENTRIES 100000 121#define BC_MAXBATCHES 255 122 123/* 124 * BC_OP_STOP - stop the cache engine. 125 * 126 * The history list mount size is returned in bc_data1_size and 127 * entry list size is returned in bc_data2_size (in bytes). If the history 128 * list was truncated, bc_data1_size will be 0 and BC_OP_HISTORY must still be 129 * called to clear the buffer. 130 */ 131 132/* 133 * BC_OP_JETTISON - jettison the cache. 134 * 135 * No parameters 136 */ 137 138/* 139 * BC_OP_HISTORY - copy out history and clear. 140 * 141 * The kernel's copy of the mount and entry history is copied into the array of 142 * BC_history_mount and BC_history_entry structures at bc_data1 and bc_data2, 143 * respectively. The cache must previously have been stopped before calling this 144 * interface out. 145 */ 146 147/* 148 * Playlist mounts represent mount points to be cached. 149 */ 150struct BC_history_mount { 151 uuid_t hm_uuid; /* The UUID of the mount */ 152 int hm_nentries; /* The number of history entries that refer to this mount */ 153}; 154 155struct BC_history_entry { 156 u_int64_t he_offset; /* data offset on device */ 157 u_int64_t he_length; /* length of data */ 158 u_int32_t he_pid; /* pid of the process that issued this IO */ 159 u_int16_t he_flags; 160#define BC_HE_HIT 0x1 /* read was satisfied from cache */ 161#define BC_HE_WRITE 0x2 /* write-through operation */ 162#define BC_HE_TAG 0x4 /* userland-set tag */ 163#define BC_HE_SHARED 0x8 /* IO was from the shared cache */ 164 u_int16_t he_mount_idx; /* index of the mount this read was on */ 165}; 166 167 168/* Number of disks and batches we can collect statistics on */ 169#define STAT_DISKMAX 8 170#define STAT_MOUNTMAX 32 171#define STAT_BATCHMAX 16 172 173/* 174 * BC_OP_STATS - return statistics. 175 * 176 * The kernel's copy of the statistics is copied into 177 * the BC_statictics structure at bc_data1 178 */ 179struct BC_statistics { 180 /* readahead */ 181 u_int ss_readahead_threads; /* number of readahead threads */ 182 u_int ss_initiated_reads; /* read operations we initiated */ 183 u_int ss_disk_initiated_reads[STAT_DISKMAX]; /* read operations we initiated per disk */ 184 u_int ss_read_blocks; /* number of blocks read */ 185 u_int ss_read_bytes; /* number of bytes read */ 186 u_int ss_read_errors; /* read errors encountered */ 187 u_int ss_read_errors_bytes; /* bytes discarded due to read errors */ 188 u_int ss_batch_bytes[STAT_DISKMAX][STAT_BATCHMAX+1]; /* number of bytes in read per batch, +1 for sum of extra batches */ 189 u_int ss_batch_late_bytes[STAT_DISKMAX][STAT_BATCHMAX+1]; /* number of bytes read during this batch 190 that were scheduled for an earlier batch */ 191 u_int ss_batch_time[STAT_DISKMAX][STAT_BATCHMAX+1]; /* msecs per batch, +1 for sum of extra batches */ 192 u_int ss_cache_time; /* msecs cache was alive */ 193 u_int ss_preload_time; /* msecs before cache started */ 194 195 u_int ss_read_bytes_lowpri; /* number of bytes read */ 196 u_int ss_batch_bytes_lowpri[STAT_DISKMAX]; /* number of bytes in read per disk */ 197 u_int ss_batch_time_lowpri[STAT_DISKMAX]; /* msecs per disk */ 198 u_int ss_disk_initiated_reads_lowpri[STAT_DISKMAX]; /* read operations we initiated per disk */ 199 200 /* inbound strategy calls (while we're recording) */ 201 u_int ss_strategy_calls; /* total strategy calls we received */ 202 u_int ss_strategy_bypassed; /* strategy calls we bypassed */ 203 u_int ss_strategy_nonread; /* strategy calls that were not reads */ 204 u_int ss_strategy_throttled; /* strategy calls marked low priority */ 205 u_int ss_strategy_noncached_mount; /* strategy calls from non-cached mounts */ 206 u_int ss_strategy_unknown; /* strategy calls that were unidentifiable */ 207 u_int ss_strategy_unknown_bytes; /* bytes of unidentifiable strategy calls */ 208 u_int ss_strategy_nonblocksize; /* strategy calls of non-blocksize-multiple size */ 209 210 /* non-cached IOs */ 211 u_int ss_strategy_hit_nocache; /* cache hits that were IOs we won't cache for next boot */ 212 u_int ss_strategy_bypass_nocache; /* cache misses that were IOs we won't cache for next boot */ 213 u_int ss_strategy_bypass_duringio_nocache; /* cache misses that were IOs we won't cache for next boot */ 214 u_int ss_hit_nocache_bytes; /* bytes hit by IOs we won't cache for next boot */ 215 u_int ss_bypass_nocache_bytes; /* bytes missed by IOs we won't cache for next boot */ 216 u_int ss_bypass_nocache_discards; /* bytes discarded by IOs we won't cache for next boot */ 217 218 /* io during readahead */ 219 u_int ss_strategy_duringio; /* total strategy calls */ 220 u_int ss_strategy_bypass_duringio; /* strategy calls we bypassed */ 221 u_int ss_strategy_bypass_duringio_rootdisk_read; /* read strategy calls we missed for the root disk */ 222 u_int ss_strategy_bypass_duringio_rootdisk_failure; /* read strategy calls we hit but failed to fulfil for the root disk */ 223 u_int ss_strategy_bypass_duringio_rootdisk_nonread; /* nonread strategy calls we bypassed for the root disk */ 224 u_int ss_strategy_forced_throttled; /* strategy calls we forced to throttle due to cutting through our readahead */ 225 u_int ss_hit_duringio; /* cache hits during active readahead */ 226 u_int ss_strategy_bypass_duringio_unfilled; /* strategy calls that hit an unfilled extent (for SSDs) */ 227 u_int ss_strategy_unfilled_lowpri; /* strategy calls that hit an unfilled low priority extent */ 228 u_int ss_strategy_blocked; /* strategy calls that blocked on future readhead */ 229 u_int ss_strategy_timedout; /* strategy calls that timed out */ 230 u_int ss_strategy_time_longest_blocked; /* longest time a strategy calls spent blocked on our cache (in milliseconds) */ 231 u_int ss_strategy_time_blocked; /* milliseconds strategy calls spent blocked on our cache */ 232 233 /* extents */ 234 u_int ss_total_extents; /* number of extents in the cache */ 235 u_int ss_extents_clipped; /* number of extents clipped due to page boundaries */ 236 u_int ss_extent_lookups; /* number of extents searched for */ 237 u_int ss_extent_hits; /* number of extents matched (cache hits) */ 238 u_int ss_hit_multiple; /* cache hits that touched more than one extent */ 239 u_int ss_hit_aborted; /* cache hits not filled due to aborted extents */ 240 u_int ss_hit_blkmissing; /* cache hits not filled due to missing blocks */ 241 u_int ss_hit_stolen; /* cache hits not filled due to stolen pages */ 242 u_int ss_hit_failure; /* cache hits not filled due to other failures */ 243 244 /* mounts */ 245 u_int ss_total_mounts; /* number of mounts in the cache */ 246 u_int ss_history_mount_no_uuid; /* number of mounts seen without a uuid */ 247 248 /* byte/page activity */ 249 u_int ss_requested_bytes; 250 u_int ss_requested_bytes_m[STAT_MOUNTMAX]; 251 u_int ss_hit_bytes; /* number of bytes vacated due to read hits */ 252 u_int ss_hit_bytes_m[STAT_MOUNTMAX]; /* number of bytes vacated due to read hits */ 253 u_int ss_shared_bytes; /* number of bytes read from the shared cache */ 254 u_int ss_hit_shared_bytes; /* number of bytes hit IOs in the shared cache */ 255 u_int ss_stolen_bytes; /* number of bytes lost to pageout or contig mem */ 256 u_int ss_write_discards; /* bytes discarded due to overwriting */ 257 u_int ss_read_discards; /* bytes discarded due to incoming reads */ 258 u_int ss_error_discards; /* bytes discarded due to failure to fulfil a cache hit */ 259 u_int ss_spurious_bytes; /* number of btyes not consumed */ 260 u_int ss_hit_bytes_afterhistory; /* bytes fulfilled after history recording was complete */ 261 u_int ss_lost_bytes_afterhistory; /* bytes lost after history recording was complete */ 262 263 /* history activity */ 264 u_int ss_history_bytes; /* number of bytes contained in the history we've seen for this boot */ 265 u_int ss_history_time; /* msecs hisotry was active */ 266 u_int ss_history_reads; /* number of reads we saw during initial boot */ 267 u_int ss_history_writes; /* number of writes we saw during initial boot */ 268 u_int ss_history_entries; /* number of history entries we've created this boot */ 269 u_int ss_history_mounts; /* number of allocated history mounts we had for the last recording */ 270 u_int ss_history_unknown; /* history calls we couldn't find a mount for */ 271 u_int ss_history_unknown_bytes; /* bytes history calls we couldn't find a mount for */ 272 u_int ss_history_num_recordings; /* number of recordings we've has this boot */ 273 274 /* current status */ 275 u_int ss_cache_flags; /* current cache flags */ 276}; 277 278/* 279 * In-memory BootCache playlist structure 280 */ 281struct BC_playlist { 282 int p_nmounts; /* number of mounts */ 283 int p_nentries; /* number of entries */ 284 struct BC_playlist_mount *p_mounts; /* array of mounts */ 285 struct BC_playlist_entry *p_entries; /* array of entries */ 286}; 287 288/* 289 * In-memory BootCache history structure 290 */ 291struct BC_history { 292 int h_nmounts; /* number of mounts */ 293 int h_nentries; /* number of entries */ 294 struct BC_history_mount *h_mounts; /* array of mounts */ 295 struct BC_history_entry *h_entries; /* array of entries */ 296}; 297 298#ifndef KERNEL 299/* 300 * Support library functions. 301 */ 302extern int BC_read_playlist(const char *, struct BC_playlist **); 303extern int BC_write_playlist(const char *, const struct BC_playlist *); 304extern int BC_merge_playlists(struct BC_playlist *, const struct BC_playlist *); 305extern void BC_sort_playlist(struct BC_playlist *); 306extern int BC_coalesce_playlist(struct BC_playlist *); 307extern int BC_playlist_for_file(int fd, struct BC_playlist** ppc); 308extern int BC_playlist_for_filename(int fd, const char *fname, off_t maxsize, struct BC_playlist** ppc); 309extern int BC_verify_playlist(const struct BC_playlist *); 310extern void BC_free_playlist(struct BC_playlist *); 311#define PC_FREE_ZERO(pc) do { if (pc) { BC_free_playlist(pc); (pc) = NULL; } } while (0) 312extern void BC_free_history(struct BC_history *); 313#define HC_FREE_ZERO(hc) do { if (hc) { BC_free_history(hc); (hc) = NULL; } } while (0) 314extern int BC_fetch_statistics(struct BC_statistics **); 315extern int BC_convert_history(const struct BC_history *, struct BC_playlist **); 316extern int BC_start(struct BC_playlist *); 317extern int BC_stop(struct BC_history **); 318extern int BC_notify_mount(void); 319extern int BC_test(void); 320extern int BC_jettison(void); 321extern int BC_print_statistics(char *, struct BC_statistics *); 322extern int BC_print_history(char *, struct BC_history *); 323extern int BC_tag_history(void); 324extern int BC_unload(void); 325#endif 326