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