]> git.saurik.com Git - apple/system_cmds.git/blob - fs_usage.tproj/fs_usage.c
52894219fd8b7ea599984c6a9cea4248f1caf7af
[apple/system_cmds.git] / fs_usage.tproj / fs_usage.c
1 /*
2 * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 /*
26 * SDKROOT=macosx.internal cc -I`xcrun -sdk macosx.internal --show-sdk-path`/System/Library/Frameworks/System.framework/Versions/B/PrivateHeaders -arch x86_64 -Os -lktrace -lutil -o fs_usage fs_usage.c
27 */
28
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <signal.h>
32 #include <strings.h>
33 #include <fcntl.h>
34 #include <aio.h>
35 #include <string.h>
36 #include <dirent.h>
37 #include <libc.h>
38 #include <termios.h>
39 #include <errno.h>
40 #include <err.h>
41 #include <libutil.h>
42
43 #include <ktrace.h>
44 #include <assert.h>
45
46 #include <sys/disk.h>
47 #include <sys/fcntl.h>
48 #include <sys/file.h>
49 #include <sys/ioctl.h>
50 #include <sys/mman.h>
51 #include <sys/param.h>
52 #include <sys/socket.h>
53 #include <sys/syslimits.h>
54 #include <sys/time.h>
55 #include <sys/types.h>
56
57 #import <mach/clock_types.h>
58 #import <mach/mach_time.h>
59
60 /*
61 * MAXCOLS controls when extra data kicks in.
62 * MAX_WIDE_MODE_COLS controls -w mode to get even wider data in path.
63 */
64 #define MAXCOLS 132
65 #define MAX_WIDE_MODE_COLS 264
66 #define MAXWIDTH MAX_WIDE_MODE_COLS + 64
67
68 typedef struct th_info {
69 struct th_info *next;
70 uintptr_t thread;
71
72 /* this is needed for execve()/posix_spawn(), because the command name at the end probe is the new name, which we don't want */
73 char command[MAXCOMLEN + 1];
74
75 /*
76 * sometimes a syscall can cause multiple VFS_LOOKUPs of the same vnode with multiple paths
77 * (e.g., one absolute, one relative). traditional fs_usage behavior was to display the
78 * *first* lookup, so we need to save it off once we see it.
79 */
80 unsigned long vnodeid; /* the vp of the VFS_LOOKUP we're currently in, 0 if we are not in one */
81 char pathname[MAXPATHLEN];
82 char pathname2[MAXPATHLEN];
83 char *newest_pathname; /* points to pathname2 if it's filled, otherwise pathname if it's filled, otherwise NULL */
84
85 int pid;
86 int type;
87 unsigned long arg1;
88 unsigned long arg2;
89 unsigned long arg3;
90 unsigned long arg4;
91 unsigned long arg5;
92 unsigned long arg6;
93 unsigned long arg7;
94 unsigned long arg8;
95 int waited;
96 uint64_t stime;
97 } *th_info_t;
98
99 struct diskio {
100 struct diskio *next;
101 struct diskio *prev;
102 unsigned long type;
103 unsigned long bp;
104 unsigned long dev;
105 unsigned long blkno;
106 unsigned long iosize;
107 unsigned long io_errno;
108 unsigned long is_meta;
109 uint64_t vnodeid;
110 uintptr_t issuing_thread;
111 pid_t issuing_pid;
112 uintptr_t completion_thread;
113 char issuing_command[MAXCOMLEN + 1];
114 uint64_t issued_time;
115 uint64_t completed_time;
116 struct timeval completed_walltime;
117 uint32_t bc_info;
118 };
119
120 #define HASH_SIZE 1024
121 #define HASH_MASK (HASH_SIZE - 1)
122
123 void setup_ktrace_callbacks(void);
124 void extend_syscall(uintptr_t thread, int type, ktrace_event_t event);
125
126 /* printing routines */
127 bool check_filter_mode(pid_t pid, th_info_t ti, unsigned long type, int error, int retval, char *sc_name);
128 void format_print(th_info_t ti, char *sc_name, ktrace_event_t event, unsigned long type, int format, uint64_t now, uint64_t stime, int waited, const char *pathname, struct diskio *dio);
129
130 /* metadata info hash routines */
131 void meta_add_name(uint64_t blockno, const char *pathname);
132 const char *meta_find_name(uint64_t blockno);
133 void meta_delete_all(void);
134
135 /* event ("thread info") routines */
136 void event_enter(int type, ktrace_event_t event);
137 void event_exit(char *sc_name, int type, ktrace_event_t event, int format);
138 th_info_t event_find(uintptr_t thread, int type);
139 void event_delete(th_info_t ti_to_delete);
140 void event_delete_all(void);
141 void event_mark_thread_waited(uintptr_t);
142
143 /* network fd set routines */
144 void fd_set_is_network(pid_t pid, unsigned long fd, bool set);
145 bool fd_is_network(pid_t pid, unsigned long fd);
146 void fd_clear_pid(pid_t pid);
147 void fd_clear_all(void);
148
149 /* shared region address lookup routines */
150 void init_shared_cache_mapping(void);
151 void lookup_name(uint64_t user_addr, char **type, char **name);
152
153 /* disk I/O tracking routines */
154 struct diskio *diskio_start(unsigned long type, unsigned long bp, unsigned long dev, unsigned long blkno, unsigned long iosize, ktrace_event_t event);
155 struct diskio *diskio_find(unsigned long bp);
156 struct diskio *diskio_complete(unsigned long bp, unsigned long io_errno, unsigned long resid, uintptr_t thread, uint64_t curtime, struct timeval curtime_wall);
157 void diskio_print(struct diskio *dio);
158 void diskio_free(struct diskio *dio);
159
160 /* disk name routines */
161 #define NFS_DEV -1
162 #define CS_DEV -2
163 char *generate_cs_disk_name(unsigned long dev, char *s);
164 char *find_disk_name(unsigned long dev);
165 void cache_disk_names(void);
166
167 #define CLASS_MASK 0xff000000
168 #define CSC_MASK 0xffff0000
169 #define BSC_INDEX(type) ((type >> 2) & 0x3fff)
170
171 #define MACH_vmfault 0x01300008
172 #define MACH_pageout 0x01300004
173 #define MACH_sched 0x01400000
174 #define MACH_stkhandoff 0x01400008
175 #define MACH_idle 0x01400024
176
177 #define BSC_thread_terminate 0x040c05a4
178
179 #define HFS_update 0x3018000
180 #define HFS_modify_block_end 0x3018004
181
182 #define Throttled 0x3010184
183 #define SPEC_ioctl 0x3060000
184 #define SPEC_unmap_info 0x3060004
185 #define proc_exit 0x4010004
186
187 #define BC_IO_HIT 0x03070010
188 #define BC_IO_HIT_STALLED 0x03070020
189 #define BC_IO_MISS 0x03070040
190 #define BC_IO_MISS_CUT_THROUGH 0x03070080
191 #define BC_PLAYBACK_IO 0x03070100
192 #define BC_STR(s) ( \
193 (s == BC_IO_HIT) ? "HIT" : \
194 (s == BC_IO_HIT_STALLED) ? "STALL" : \
195 (s == BC_IO_MISS) ? "MISS" : \
196 (s == BC_IO_MISS_CUT_THROUGH) ? "CUT" : \
197 (s == BC_PLAYBACK_IO) ? "PLBK" : \
198 (s == 0x0) ? "NONE" : "UNKN" )
199
200 #define P_DISKIO_READ (DKIO_READ << 2)
201 #define P_DISKIO_ASYNC (DKIO_ASYNC << 2)
202 #define P_DISKIO_META (DKIO_META << 2)
203 #define P_DISKIO_PAGING (DKIO_PAGING << 2)
204 #define P_DISKIO_THROTTLE (DKIO_THROTTLE << 2)
205 #define P_DISKIO_PASSIVE (DKIO_PASSIVE << 2)
206 #define P_DISKIO_NOCACHE (DKIO_NOCACHE << 2)
207 #define P_DISKIO_TIER_MASK (DKIO_TIER_MASK << 2)
208 #define P_DISKIO_TIER_SHIFT (DKIO_TIER_SHIFT + 2)
209 #define P_DISKIO_TIER_UPGRADE (DKIO_TIER_UPGRADE << 2)
210
211 #define P_DISKIO (FSDBG_CODE(DBG_DKRW, 0))
212 #define P_DISKIO_DONE (P_DISKIO | (DKIO_DONE << 2))
213 #define P_DISKIO_TYPE (P_DISKIO | P_DISKIO_READ | P_DISKIO_META | P_DISKIO_PAGING)
214 #define P_DISKIO_MASK (CSC_MASK | 0x4)
215
216 #define P_WrData (P_DISKIO)
217 #define P_RdData (P_DISKIO | P_DISKIO_READ)
218 #define P_WrMeta (P_DISKIO | P_DISKIO_META)
219 #define P_RdMeta (P_DISKIO | P_DISKIO_META | P_DISKIO_READ)
220 #define P_PgOut (P_DISKIO | P_DISKIO_PAGING)
221 #define P_PgIn (P_DISKIO | P_DISKIO_PAGING | P_DISKIO_READ)
222
223 #define P_CS_Class 0x0a000000 // DBG_CORESTORAGE
224 #define P_CS_Type_Mask 0xfffffff0
225 #define P_CS_IO_Done 0x00000004
226
227 #define P_CS_ReadChunk 0x0a000200 // chopped up request
228 #define P_CS_WriteChunk 0x0a000210
229 #define P_CS_MetaRead 0x0a000300 // meta data
230 #define P_CS_MetaWrite 0x0a000310
231 #define P_CS_TransformRead 0x0a000500 // background transform
232 #define P_CS_TransformWrite 0x0a000510
233 #define P_CS_MigrationRead 0x0a000600 // composite disk block migration
234 #define P_CS_MigrationWrite 0x0a000610
235 #define P_CS_SYNC_DISK 0x0a010000
236
237 #define MSC_map_fd 0x010c00ac
238
239 #define BSC_BASE 0x040C0000
240
241 // Network related codes
242 #define BSC_recvmsg 0x040C006C
243 #define BSC_sendmsg 0x040C0070
244 #define BSC_recvfrom 0x040C0074
245 #define BSC_accept 0x040C0078
246 #define BSC_select 0x040C0174
247 #define BSC_socket 0x040C0184
248 #define BSC_connect 0x040C0188
249 #define BSC_bind 0x040C01A0
250 #define BSC_listen 0x040C01A8
251 #define BSC_sendto 0x040C0214
252 #define BSC_socketpair 0x040C021C
253 #define BSC_recvmsg_nocancel 0x040c0644
254 #define BSC_sendmsg_nocancel 0x040c0648
255 #define BSC_recvfrom_nocancel 0x040c064c
256 #define BSC_accept_nocancel 0x040c0650
257 #define BSC_connect_nocancel 0x040c0664
258 #define BSC_sendto_nocancel 0x040c0674
259
260 #define BSC_exit 0x040C0004
261 #define BSC_read 0x040C000C
262 #define BSC_write 0x040C0010
263 #define BSC_open 0x040C0014
264 #define BSC_close 0x040C0018
265 #define BSC_link 0x040C0024
266 #define BSC_unlink 0x040C0028
267 #define BSC_chdir 0x040c0030
268 #define BSC_fchdir 0x040c0034
269 #define BSC_mknod 0x040C0038
270 #define BSC_chmod 0x040C003C
271 #define BSC_chown 0x040C0040
272 #define BSC_getfsstat 0x040C0048
273 #define BSC_access 0x040C0084
274 #define BSC_chflags 0x040C0088
275 #define BSC_fchflags 0x040C008C
276 #define BSC_sync 0x040C0090
277 #define BSC_dup 0x040C00A4
278 #define BSC_ioctl 0x040C00D8
279 #define BSC_revoke 0x040C00E0
280 #define BSC_symlink 0x040C00E4
281 #define BSC_readlink 0x040C00E8
282 #define BSC_execve 0x040C00EC
283 #define BSC_umask 0x040C00F0
284 #define BSC_chroot 0x040C00F4
285 #define BSC_msync 0x040C0104
286 #define BSC_dup2 0x040C0168
287 #define BSC_fcntl 0x040C0170
288 #define BSC_fsync 0x040C017C
289 #define BSC_readv 0x040C01E0
290 #define BSC_writev 0x040C01E4
291 #define BSC_fchown 0x040C01EC
292 #define BSC_fchmod 0x040C01F0
293 #define BSC_rename 0x040C0200
294 #define BSC_flock 0x040C020C
295 #define BSC_mkfifo 0x040C0210
296 #define BSC_mkdir 0x040C0220
297 #define BSC_rmdir 0x040C0224
298 #define BSC_utimes 0x040C0228
299 #define BSC_futimes 0x040C022C
300 #define BSC_pread 0x040C0264
301 #define BSC_pwrite 0x040C0268
302 #define BSC_statfs 0x040C0274
303 #define BSC_fstatfs 0x040C0278
304 #define BSC_unmount 0x040C027C
305 #define BSC_mount 0x040C029C
306 #define BSC_fdatasync 0x040C02EC
307 #define BSC_stat 0x040C02F0
308 #define BSC_fstat 0x040C02F4
309 #define BSC_lstat 0x040C02F8
310 #define BSC_pathconf 0x040C02FC
311 #define BSC_fpathconf 0x040C0300
312 #define BSC_getdirentries 0x040C0310
313 #define BSC_mmap 0x040c0314
314 #define BSC_lseek 0x040c031c
315 #define BSC_truncate 0x040C0320
316 #define BSC_ftruncate 0x040C0324
317 #define BSC_undelete 0x040C0334
318 #define BSC_open_dprotected_np 0x040C0360
319 #define BSC_getattrlist 0x040C0370
320 #define BSC_setattrlist 0x040C0374
321 #define BSC_getdirentriesattr 0x040C0378
322 #define BSC_exchangedata 0x040C037C
323 #define BSC_checkuseraccess 0x040C0380
324 #define BSC_searchfs 0x040C0384
325 #define BSC_delete 0x040C0388
326 #define BSC_copyfile 0x040C038C
327 #define BSC_fgetattrlist 0x040C0390
328 #define BSC_fsetattrlist 0x040C0394
329 #define BSC_getxattr 0x040C03A8
330 #define BSC_fgetxattr 0x040C03AC
331 #define BSC_setxattr 0x040C03B0
332 #define BSC_fsetxattr 0x040C03B4
333 #define BSC_removexattr 0x040C03B8
334 #define BSC_fremovexattr 0x040C03BC
335 #define BSC_listxattr 0x040C03C0
336 #define BSC_flistxattr 0x040C03C4
337 #define BSC_fsctl 0x040C03C8
338 #define BSC_posix_spawn 0x040C03D0
339 #define BSC_ffsctl 0x040C03D4
340 #define BSC_open_extended 0x040C0454
341 #define BSC_umask_extended 0x040C0458
342 #define BSC_stat_extended 0x040C045C
343 #define BSC_lstat_extended 0x040C0460
344 #define BSC_fstat_extended 0x040C0464
345 #define BSC_chmod_extended 0x040C0468
346 #define BSC_fchmod_extended 0x040C046C
347 #define BSC_access_extended 0x040C0470
348 #define BSC_mkfifo_extended 0x040C048C
349 #define BSC_mkdir_extended 0x040C0490
350 #define BSC_aio_fsync 0x040C04E4
351 #define BSC_aio_return 0x040C04E8
352 #define BSC_aio_suspend 0x040C04EC
353 #define BSC_aio_cancel 0x040C04F0
354 #define BSC_aio_error 0x040C04F4
355 #define BSC_aio_read 0x040C04F8
356 #define BSC_aio_write 0x040C04FC
357 #define BSC_lio_listio 0x040C0500
358 #define BSC_sendfile 0x040C0544
359 #define BSC_stat64 0x040C0548
360 #define BSC_fstat64 0x040C054C
361 #define BSC_lstat64 0x040C0550
362 #define BSC_stat64_extended 0x040C0554
363 #define BSC_lstat64_extended 0x040C0558
364 #define BSC_fstat64_extended 0x040C055C
365 #define BSC_getdirentries64 0x040C0560
366 #define BSC_statfs64 0x040C0564
367 #define BSC_fstatfs64 0x040C0568
368 #define BSC_getfsstat64 0x040C056C
369 #define BSC_pthread_chdir 0x040C0570
370 #define BSC_pthread_fchdir 0x040C0574
371 #define BSC_lchown 0x040C05B0
372
373 #define BSC_read_nocancel 0x040c0630
374 #define BSC_write_nocancel 0x040c0634
375 #define BSC_open_nocancel 0x040c0638
376 #define BSC_close_nocancel 0x040c063c
377 #define BSC_msync_nocancel 0x040c0654
378 #define BSC_fcntl_nocancel 0x040c0658
379 #define BSC_select_nocancel 0x040c065c
380 #define BSC_fsync_nocancel 0x040c0660
381 #define BSC_readv_nocancel 0x040c066c
382 #define BSC_writev_nocancel 0x040c0670
383 #define BSC_pread_nocancel 0x040c0678
384 #define BSC_pwrite_nocancel 0x040c067c
385 #define BSC_aio_suspend_nocancel 0x40c0694
386 #define BSC_guarded_open_np 0x040c06e4
387 #define BSC_guarded_close_np 0x040c06e8
388
389 #define BSC_fsgetpath 0x040c06ac
390
391 #define BSC_getattrlistbulk 0x040c0734
392
393 #define BSC_openat 0x040c073c
394 #define BSC_openat_nocancel 0x040c0740
395 #define BSC_renameat 0x040c0744
396 #define BSC_chmodat 0x040c074c
397 #define BSC_chownat 0x040c0750
398 #define BSC_fstatat 0x040c0754
399 #define BSC_fstatat64 0x040c0758
400 #define BSC_linkat 0x040c075c
401 #define BSC_unlinkat 0x040c0760
402 #define BSC_readlinkat 0x040c0764
403 #define BSC_symlinkat 0x040c0768
404 #define BSC_mkdirat 0x040c076c
405 #define BSC_getattrlistat 0x040c0770
406
407 #define BSC_msync_extended 0x040e0104
408 #define BSC_pread_extended 0x040e0264
409 #define BSC_pwrite_extended 0x040e0268
410 #define BSC_mmap_extended 0x040e0314
411 #define BSC_mmap_extended2 0x040f0314
412
413 #define FMT_NOTHING -1
414 #define FMT_DEFAULT 0
415 #define FMT_FD 1
416 #define FMT_FD_IO 2
417 #define FMT_FD_2 3
418 #define FMT_SOCKET 4
419 #define FMT_PGIN 5
420 #define FMT_PGOUT 6
421 #define FMT_CACHEHIT 7
422 #define FMT_DISKIO 8
423 #define FMT_LSEEK 9
424 #define FMT_PREAD 10
425 #define FMT_FTRUNC 11
426 #define FMT_TRUNC 12
427 #define FMT_SELECT 13
428 #define FMT_OPEN 14
429 #define FMT_AIO_FSYNC 15
430 #define FMT_AIO_RETURN 16
431 #define FMT_AIO_SUSPEND 17
432 #define FMT_AIO_CANCEL 18
433 #define FMT_AIO 19
434 #define FMT_LIO_LISTIO 20
435 #define FMT_MSYNC 21
436 #define FMT_FCNTL 22
437 #define FMT_ACCESS 23
438 #define FMT_CHMOD 24
439 #define FMT_FCHMOD 25
440 #define FMT_CHMOD_EXT 26
441 #define FMT_FCHMOD_EXT 27
442 #define FMT_CHFLAGS 28
443 #define FMT_FCHFLAGS 29
444 #define FMT_IOCTL 30
445 #define FMT_MMAP 31
446 #define FMT_UMASK 32
447 #define FMT_SENDFILE 33
448 #define FMT_IOCTL_SYNC 34
449 #define FMT_MOUNT 35
450 #define FMT_UNMOUNT 36
451 #define FMT_DISKIO_CS 37
452 #define FMT_SYNC_DISK_CS 38
453 #define FMT_IOCTL_UNMAP 39
454 #define FMT_UNMAP_INFO 40
455 #define FMT_HFS_update 41
456 #define FMT_FLOCK 42
457 #define FMT_AT 43
458 #define FMT_CHMODAT 44
459 #define FMT_OPENAT 45
460 #define FMT_RENAMEAT 46
461 #define FMT_IOCTL_SYNCCACHE 47
462
463 #define DBG_FUNC_ALL (DBG_FUNC_START | DBG_FUNC_END)
464
465 #pragma mark global state
466
467 ktrace_session_t s;
468 bool BC_flag = false;
469 bool RAW_flag = false;
470 bool wideflag = false;
471 bool include_waited_flag = false;
472 bool want_kernel_task = true;
473 dispatch_source_t stop_timer, sigquit_source, sigpipe_source, sighup_source, sigterm_source, sigwinch_source;
474 uint64_t mach_time_of_first_event;
475 uint64_t start_time_ns = 0;
476 uint64_t end_time_ns = UINT64_MAX;
477 unsigned int columns = 0;
478
479 /*
480 * Network only or filesystem only output filter
481 * Default of zero means report all activity - no filtering
482 */
483 #define FILESYS_FILTER 0x01
484 #define NETWORK_FILTER 0x02
485 #define EXEC_FILTER 0x08
486 #define PATHNAME_FILTER 0x10
487 #define DISKIO_FILTER 0x20
488 #define DEFAULT_DO_NOT_FILTER 0x00
489
490 int filter_mode = DEFAULT_DO_NOT_FILTER;
491 bool show_cachehits = false;
492
493 #pragma mark syscall lookup table
494
495 #define MAX_BSD_SYSCALL 526
496
497 struct bsd_syscall {
498 char *sc_name;
499 int sc_format;
500 };
501
502 #define NORMAL_SYSCALL(name) \
503 [BSC_INDEX(BSC_##name)] = {#name, FMT_DEFAULT}
504
505 #define SYSCALL(name, format) \
506 [BSC_INDEX(BSC_##name)] = {#name, format}
507
508 #define SYSCALL_NAMED(name, displayname, format) \
509 [BSC_INDEX(BSC_##name)] = {#displayname, format}
510
511 #define SYSCALL_WITH_NOCANCEL(name, format) \
512 [BSC_INDEX(BSC_##name)] = {#name, format}, \
513 [BSC_INDEX(BSC_##name##_nocancel)] = {#name, format}
514
515 const struct bsd_syscall bsd_syscalls[MAX_BSD_SYSCALL] = {
516 SYSCALL(sendfile, FMT_FD), /* this should be changed to FMT_SENDFILE once we add an extended info trace event */
517 SYSCALL_WITH_NOCANCEL(recvmsg, FMT_FD_IO),
518 SYSCALL_WITH_NOCANCEL(sendmsg, FMT_FD_IO),
519 SYSCALL_WITH_NOCANCEL(recvfrom, FMT_FD_IO),
520 SYSCALL_WITH_NOCANCEL(sendto, FMT_FD_IO),
521 SYSCALL_WITH_NOCANCEL(select, FMT_SELECT),
522 SYSCALL_WITH_NOCANCEL(accept, FMT_FD_2),
523 SYSCALL(socket, FMT_SOCKET),
524 SYSCALL_WITH_NOCANCEL(connect, FMT_FD),
525 SYSCALL(bind, FMT_FD),
526 SYSCALL(listen, FMT_FD),
527 SYSCALL(mmap, FMT_MMAP),
528 NORMAL_SYSCALL(socketpair),
529 NORMAL_SYSCALL(getxattr),
530 NORMAL_SYSCALL(setxattr),
531 NORMAL_SYSCALL(removexattr),
532 NORMAL_SYSCALL(listxattr),
533 NORMAL_SYSCALL(stat),
534 NORMAL_SYSCALL(stat64),
535 NORMAL_SYSCALL(stat_extended),
536 SYSCALL_NAMED(stat64_extended, stat_extended64, FMT_DEFAULT), /* should be stat64_extended ? */
537 SYSCALL(mount, FMT_MOUNT),
538 SYSCALL(unmount, FMT_UNMOUNT),
539 NORMAL_SYSCALL(exit),
540 NORMAL_SYSCALL(execve),
541 NORMAL_SYSCALL(posix_spawn),
542 SYSCALL_WITH_NOCANCEL(open, FMT_OPEN),
543 SYSCALL(open_extended, FMT_OPEN),
544 SYSCALL(guarded_open_np, FMT_OPEN),
545 SYSCALL_NAMED(open_dprotected_np, open_dprotected, FMT_OPEN),
546 SYSCALL(dup, FMT_FD_2),
547 SYSCALL(dup2, FMT_FD_2),
548 SYSCALL_WITH_NOCANCEL(close, FMT_FD),
549 SYSCALL(guarded_close_np, FMT_FD),
550 SYSCALL_WITH_NOCANCEL(read, FMT_FD_IO),
551 SYSCALL_WITH_NOCANCEL(write, FMT_FD_IO),
552 SYSCALL(fgetxattr, FMT_FD),
553 SYSCALL(fsetxattr, FMT_FD),
554 SYSCALL(fremovexattr, FMT_FD),
555 SYSCALL(flistxattr, FMT_FD),
556 SYSCALL(fstat, FMT_FD),
557 SYSCALL(fstat64, FMT_FD),
558 SYSCALL(fstat_extended, FMT_FD),
559 SYSCALL(fstat64_extended, FMT_FD),
560 NORMAL_SYSCALL(lstat),
561 NORMAL_SYSCALL(lstat64),
562 NORMAL_SYSCALL(lstat_extended),
563 SYSCALL_NAMED(lstat64_extended, lstat_extended64, FMT_DEFAULT),
564 NORMAL_SYSCALL(link),
565 NORMAL_SYSCALL(unlink),
566 NORMAL_SYSCALL(mknod),
567 SYSCALL(umask, FMT_UMASK),
568 SYSCALL(umask_extended, FMT_UMASK),
569 SYSCALL(chmod, FMT_CHMOD),
570 SYSCALL(chmod_extended, FMT_CHMOD_EXT),
571 SYSCALL(fchmod, FMT_FCHMOD),
572 SYSCALL(fchmod_extended, FMT_FCHMOD_EXT),
573 NORMAL_SYSCALL(chown),
574 NORMAL_SYSCALL(lchown),
575 SYSCALL(fchown, FMT_FD),
576 SYSCALL(access, FMT_ACCESS),
577 NORMAL_SYSCALL(access_extended),
578 NORMAL_SYSCALL(chdir),
579 NORMAL_SYSCALL(pthread_chdir),
580 NORMAL_SYSCALL(chroot),
581 NORMAL_SYSCALL(utimes),
582 SYSCALL_NAMED(delete, delete-Carbon, FMT_DEFAULT),
583 NORMAL_SYSCALL(undelete),
584 NORMAL_SYSCALL(revoke),
585 NORMAL_SYSCALL(fsctl),
586 SYSCALL(ffsctl, FMT_FD),
587 SYSCALL(chflags, FMT_CHFLAGS),
588 SYSCALL(fchflags, FMT_FCHFLAGS),
589 SYSCALL(fchdir, FMT_FD),
590 SYSCALL(pthread_fchdir, FMT_FD),
591 SYSCALL(futimes, FMT_FD),
592 NORMAL_SYSCALL(sync),
593 NORMAL_SYSCALL(symlink),
594 NORMAL_SYSCALL(readlink),
595 SYSCALL_WITH_NOCANCEL(fsync, FMT_FD),
596 SYSCALL(fdatasync, FMT_FD),
597 SYSCALL_WITH_NOCANCEL(readv, FMT_FD_IO),
598 SYSCALL_WITH_NOCANCEL(writev, FMT_FD_IO),
599 SYSCALL_WITH_NOCANCEL(pread, FMT_PREAD),
600 SYSCALL_WITH_NOCANCEL(pwrite, FMT_PREAD),
601 NORMAL_SYSCALL(mkdir),
602 NORMAL_SYSCALL(mkdir_extended),
603 NORMAL_SYSCALL(mkfifo),
604 NORMAL_SYSCALL(mkfifo_extended),
605 NORMAL_SYSCALL(rmdir),
606 NORMAL_SYSCALL(statfs),
607 NORMAL_SYSCALL(statfs64),
608 NORMAL_SYSCALL(getfsstat),
609 NORMAL_SYSCALL(getfsstat64),
610 SYSCALL(fstatfs, FMT_FD),
611 SYSCALL(fstatfs64, FMT_FD),
612 NORMAL_SYSCALL(pathconf),
613 SYSCALL(fpathconf, FMT_FD),
614 SYSCALL(getdirentries, FMT_FD_IO),
615 SYSCALL(getdirentries64, FMT_FD_IO),
616 SYSCALL(lseek, FMT_LSEEK),
617 SYSCALL(truncate, FMT_TRUNC),
618 SYSCALL(ftruncate, FMT_FTRUNC),
619 SYSCALL(flock, FMT_FLOCK),
620 NORMAL_SYSCALL(getattrlist),
621 NORMAL_SYSCALL(setattrlist),
622 SYSCALL(fgetattrlist, FMT_FD),
623 SYSCALL(fsetattrlist, FMT_FD),
624 SYSCALL(getdirentriesattr, FMT_FD),
625 NORMAL_SYSCALL(exchangedata),
626 NORMAL_SYSCALL(rename),
627 NORMAL_SYSCALL(copyfile),
628 NORMAL_SYSCALL(checkuseraccess),
629 NORMAL_SYSCALL(searchfs),
630 SYSCALL(aio_fsync, FMT_AIO_FSYNC),
631 SYSCALL(aio_return, FMT_AIO_RETURN),
632 SYSCALL_WITH_NOCANCEL(aio_suspend, FMT_AIO_SUSPEND),
633 SYSCALL(aio_cancel, FMT_AIO_CANCEL),
634 SYSCALL(aio_error, FMT_AIO),
635 SYSCALL(aio_read, FMT_AIO),
636 SYSCALL(aio_write, FMT_AIO),
637 SYSCALL(lio_listio, FMT_LIO_LISTIO),
638 SYSCALL_WITH_NOCANCEL(msync, FMT_MSYNC),
639 SYSCALL_WITH_NOCANCEL(fcntl, FMT_FCNTL),
640 SYSCALL(ioctl, FMT_IOCTL),
641 NORMAL_SYSCALL(fsgetpath),
642 NORMAL_SYSCALL(getattrlistbulk),
643 SYSCALL_WITH_NOCANCEL(openat, FMT_OPENAT), /* open_nocancel() was previously shown as "open_nocanel" (note spelling) */
644 SYSCALL(renameat, FMT_RENAMEAT),
645 SYSCALL(chmodat, FMT_CHMODAT),
646 SYSCALL(chownat, FMT_AT),
647 SYSCALL(fstatat, FMT_AT),
648 SYSCALL(fstatat64, FMT_AT),
649 SYSCALL(linkat, FMT_AT),
650 SYSCALL(unlinkat, FMT_AT),
651 SYSCALL(readlinkat, FMT_AT),
652 SYSCALL(symlinkat, FMT_AT),
653 SYSCALL(mkdirat, FMT_AT),
654 SYSCALL(getattrlistat, FMT_AT),
655 };
656
657 static void
658 get_screenwidth(void)
659 {
660 struct winsize size;
661
662 columns = MAXCOLS;
663
664 if (isatty(STDOUT_FILENO)) {
665 if (ioctl(1, TIOCGWINSZ, &size) != -1) {
666 columns = size.ws_col;
667
668 if (columns > MAXWIDTH)
669 columns = MAXWIDTH;
670 }
671 }
672 }
673
674 static uint64_t
675 mach_to_nano(uint64_t mach)
676 {
677 uint64_t nanoseconds = 0;
678 assert(ktrace_convert_timestamp_to_nanoseconds(s, mach, &nanoseconds) == 0);
679
680 return nanoseconds;
681 }
682
683 static void
684 exit_usage(void)
685 {
686 const char *myname;
687
688 myname = getprogname();
689
690 fprintf(stderr, "Usage: %s [-e] [-w] [-f mode] [-b] [-t seconds] [-R rawfile [-S start_time] [-E end_time]] [pid | cmd [pid | cmd] ...]\n", myname);
691 fprintf(stderr, " -e exclude the specified list of pids from the sample\n");
692 fprintf(stderr, " and exclude fs_usage by default\n");
693 fprintf(stderr, " -w force wider, detailed, output\n");
694 fprintf(stderr, " -f output is based on the mode provided\n");
695 fprintf(stderr, " mode = \"network\" Show network-related events\n");
696 fprintf(stderr, " mode = \"filesys\" Show filesystem-related events\n");
697 fprintf(stderr, " mode = \"pathname\" Show only pathname-related events\n");
698 fprintf(stderr, " mode = \"exec\" Show only exec and spawn events\n");
699 fprintf(stderr, " mode = \"diskio\" Show only disk I/O events\n");
700 fprintf(stderr, " mode = \"cachehit\" In addition, show cache hits\n");
701 fprintf(stderr, " -b annotate disk I/O events with BootCache info (if available)\n");
702 fprintf(stderr, " -t specifies timeout in seconds (for use in automated tools)\n");
703 fprintf(stderr, " -R specifies a raw trace file to process\n");
704 fprintf(stderr, " -S if -R is specified, selects a start point in microseconds\n");
705 fprintf(stderr, " -E if -R is specified, selects an end point in microseconds\n");
706 fprintf(stderr, " pid selects process(s) to sample\n");
707 fprintf(stderr, " cmd selects process(s) matching command string to sample\n");
708 fprintf(stderr, "By default (no options) the following processes are excluded from the output:\n");
709 fprintf(stderr, "fs_usage, Terminal, telnetd, sshd, rlogind, tcsh, csh, sh\n\n");
710
711 exit(1);
712 }
713
714 int
715 main(int argc, char *argv[])
716 {
717 char ch;
718 int rv;
719 bool exclude_pids = false;
720 double time_limit = 0.0;
721
722 get_screenwidth();
723
724 s = ktrace_session_create();
725 assert(s);
726
727 while ((ch = getopt(argc, argv, "bewf:R:S:E:t:W")) != -1) {
728 switch (ch) {
729 case 'e':
730 exclude_pids = true;
731 break;
732
733 case 'w':
734 wideflag = 1;
735 columns = MAX_WIDE_MODE_COLS;
736 break;
737
738 case 'W':
739 include_waited_flag = true;
740 break;
741
742 case 'f':
743 if (!strcmp(optarg, "network"))
744 filter_mode |= NETWORK_FILTER;
745 else if (!strcmp(optarg, "filesys"))
746 filter_mode |= FILESYS_FILTER;
747 else if (!strcmp(optarg, "cachehit"))
748 show_cachehits = true;
749 else if (!strcmp(optarg, "exec"))
750 filter_mode |= EXEC_FILTER;
751 else if (!strcmp(optarg, "pathname"))
752 filter_mode |= PATHNAME_FILTER;
753 else if (!strcmp(optarg, "diskio"))
754 filter_mode |= DISKIO_FILTER;
755
756 break;
757
758 case 'b':
759 BC_flag = true;
760 break;
761
762 case 't':
763 time_limit = atof(optarg);
764
765 break;
766
767 case 'R':
768 RAW_flag = true;
769 rv = ktrace_set_file(s, optarg);
770 if (rv) {
771 fprintf(stderr, "ERROR: reading trace from '%s' failed (%s)\n", optarg, strerror(errno));
772 exit(1);
773 }
774 break;
775
776 case 'S':
777 start_time_ns = NSEC_PER_SEC * atof(optarg);
778 break;
779
780 case 'E':
781 end_time_ns = NSEC_PER_SEC * atof(optarg);
782 break;
783
784 default:
785 exit_usage();
786 }
787 }
788
789 argc -= optind;
790 argv += optind;
791
792 if (time_limit > 0.0) {
793 if (RAW_flag) {
794 fprintf(stderr, "NOTE: time limit ignored when a raw file is specified\n");
795 } else {
796 stop_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
797 dispatch_source_set_timer(stop_timer, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * time_limit), DISPATCH_TIME_FOREVER, 0);
798 dispatch_source_set_event_handler(stop_timer, ^{
799 ktrace_end(s, 0);
800 });
801 dispatch_resume(stop_timer);
802 }
803 }
804
805 if (!RAW_flag) {
806 if (geteuid() != 0) {
807 fprintf(stderr, "'fs_usage' must be run as root...\n");
808 exit(1);
809 }
810
811 /*
812 * ktrace can't both *in*clude and *ex*clude pids, so: if we are
813 * already excluding pids, or if we are not explicitly including
814 * or excluding any pids, then exclude the defaults.
815 *
816 * if on the other hand we are explicitly including pids, we'll
817 * filter the defaults out naturally.
818 */
819 if (exclude_pids || argc == 0) {
820 ktrace_exclude_process(s, "fs_usage");
821 ktrace_exclude_process(s, "Terminal");
822 ktrace_exclude_process(s, "telnetd");
823 ktrace_exclude_process(s, "telnet");
824 ktrace_exclude_process(s, "sshd");
825 ktrace_exclude_process(s, "rlogind");
826 ktrace_exclude_process(s, "tcsh");
827 ktrace_exclude_process(s, "csh");
828 ktrace_exclude_process(s, "sh");
829 ktrace_exclude_process(s, "zsh");
830 #if TARGET_OS_EMBEDDED
831 ktrace_exclude_process(s, "dropbear");
832 #endif /* TARGET_OS_EMBEDDED */
833 }
834 }
835
836 /*
837 * If we're *in*cluding processes, also *in*clude the kernel_task, which
838 * issues trace points when disk I/Os complete. But set a flag for us to
839 * avoid showing events attributed to the kernel_task.
840 *
841 * If the user actually wants to those events, we'll change that flag in
842 * the loop below.
843 */
844 if (argc > 0 && !exclude_pids) {
845 ktrace_filter_pid(s, 0);
846 want_kernel_task = false;
847 }
848
849 /*
850 * Process the list of specified pids, and in/exclude them as
851 * appropriate.
852 */
853 while (argc > 0) {
854 pid_t pid;
855 char *name;
856 char *endptr;
857
858 name = argv[0];
859 pid = (pid_t)strtoul(name, &endptr, 10);
860
861 if (*name != '\0' && *endptr == '\0') {
862 if (exclude_pids) {
863 rv = ktrace_exclude_pid(s, pid);
864 } else {
865 if (pid == 0)
866 want_kernel_task = true;
867 else
868 rv = ktrace_filter_pid(s, pid);
869 }
870 } else {
871 if (exclude_pids) {
872 rv = ktrace_exclude_process(s, name);
873 } else {
874 if (!strcmp(name, "kernel_task"))
875 want_kernel_task = true;
876 else
877 rv = ktrace_filter_process(s, name);
878 }
879 }
880
881 if (rv == EINVAL) {
882 fprintf(stderr, "ERROR: cannot both include and exclude simultaneously\n");
883 exit(1);
884 } else {
885 assert(!rv);
886 }
887
888 argc--;
889 argv++;
890 }
891
892 /* provides SIGINT, SIGHUP, SIGPIPE, SIGTERM handlers */
893 ktrace_set_signal_handler(s);
894
895 ktrace_set_completion_handler(s, ^{
896 exit(0);
897 });
898
899 signal(SIGWINCH, SIG_IGN);
900 sigwinch_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGWINCH, 0, dispatch_get_main_queue());
901 dispatch_source_set_event_handler(sigwinch_source, ^{
902 if (!wideflag)
903 get_screenwidth();
904 });
905 dispatch_resume(sigwinch_source);
906
907 init_shared_cache_mapping();
908
909 cache_disk_names();
910
911 setup_ktrace_callbacks();
912
913 ktrace_set_dropped_events_handler(s, ^{
914 fprintf(stderr, "fs_usage: buffer overrun, events generated too quickly\n");
915
916 /* clear any state that is now potentially invalid */
917
918 event_delete_all();
919 fd_clear_all();
920 meta_delete_all();
921 });
922
923 ktrace_set_default_event_names_enabled(KTRACE_FEATURE_DISABLED);
924 ktrace_set_execnames_enabled(s, KTRACE_FEATURE_LAZY);
925 ktrace_set_vnode_paths_enabled(s, true);
926
927 rv = ktrace_start(s, dispatch_get_main_queue());
928
929 if (rv) {
930 perror("ktrace_start");
931 exit(1);
932 }
933
934 dispatch_main();
935
936 return 0;
937 }
938
939 void
940 setup_ktrace_callbacks(void)
941 {
942 ktrace_events_subclass(s, DBG_MACH, DBG_MACH_EXCP_SC, ^(ktrace_event_t event) {
943 int type;
944
945 type = event->debugid & KDBG_EVENTID_MASK;
946
947 if (type == MSC_map_fd) {
948 if (event->debugid & DBG_FUNC_START) {
949 event_enter(type, event);
950 } else {
951 event_exit("map_fd", type, event, FMT_FD);
952 }
953 }
954 });
955
956 ktrace_events_subclass(s, DBG_MACH, DBG_MACH_VM, ^(ktrace_event_t event) {
957 th_info_t ti;
958 unsigned int type;
959
960 type = event->debugid & KDBG_EVENTID_MASK;
961
962 if (type != MACH_pageout && type != MACH_vmfault)
963 return;
964
965 if (event->debugid & DBG_FUNC_START) {
966 event_enter(type, event);
967 } else {
968 switch (type) {
969 case MACH_pageout:
970 if (event->arg2)
971 event_exit("PAGE_OUT_ANON", type, event, FMT_PGOUT);
972 else
973 event_exit("PAGE_OUT_FILE", type, event, FMT_PGOUT);
974
975 break;
976
977 case MACH_vmfault:
978 if (event->arg4 == DBG_PAGEIN_FAULT)
979 event_exit("PAGE_IN", type, event, FMT_PGIN);
980 else if (event->arg4 == DBG_PAGEINV_FAULT)
981 event_exit("PAGE_IN_FILE", type, event, FMT_PGIN);
982 else if (event->arg4 == DBG_PAGEIND_FAULT)
983 event_exit("PAGE_IN_ANON", type, event, FMT_PGIN);
984 else if (event->arg4 == DBG_CACHE_HIT_FAULT)
985 event_exit("CACHE_HIT", type, event, FMT_CACHEHIT);
986 else if ((ti = event_find(event->threadid, type)))
987 event_delete(ti);
988
989 break;
990
991 default:
992 abort();
993 }
994 }
995 });
996
997 if (include_waited_flag || RAW_flag) {
998 ktrace_events_subclass(s, DBG_MACH, DBG_MACH_SCHED, ^(ktrace_event_t event) {
999 int type;
1000
1001 type = event->debugid & KDBG_EVENTID_MASK;
1002
1003 switch (type) {
1004 case MACH_idle:
1005 case MACH_sched:
1006 case MACH_stkhandoff:
1007 event_mark_thread_waited(event->threadid);
1008 }
1009 });
1010 }
1011
1012 ktrace_events_subclass(s, DBG_FSYSTEM, DBG_FSRW, ^(ktrace_event_t event) {
1013 th_info_t ti;
1014 int type;
1015
1016 type = event->debugid & KDBG_EVENTID_MASK;
1017
1018 switch (type) {
1019 case HFS_modify_block_end:
1020 /*
1021 * the expected path here is as follows:
1022 * enter syscall
1023 * look up a path, which gets stored in ti->vnode / ti->pathname
1024 * modify a metadata block -- we assume the modification has something to do with the path that was looked up
1025 * leave syscall
1026 * ...
1027 * later, someone writes that metadata block; the last path associated with it is attributed
1028 */
1029 if ((ti = event_find(event->threadid, 0))) {
1030 if (ti->newest_pathname)
1031 meta_add_name(event->arg2, ti->newest_pathname);
1032 }
1033
1034 break;
1035
1036 case VFS_LOOKUP:
1037 if (event->debugid & DBG_FUNC_START) {
1038 if ((ti = event_find(event->threadid, 0)) && !ti->vnodeid) {
1039 ti->vnodeid = event->arg1;
1040 }
1041 }
1042
1043 /* it can be both start and end */
1044
1045 if (event->debugid & DBG_FUNC_END) {
1046 if ((ti = event_find(event->threadid, 0)) && ti->vnodeid) {
1047 const char *pathname;
1048
1049 pathname = ktrace_get_path_for_vp(s, ti->vnodeid);
1050
1051 ti->vnodeid = 0;
1052
1053 if (pathname) {
1054 if (ti->pathname[0] == '\0') {
1055 strncpy(ti->pathname, pathname, MAXPATHLEN);
1056 ti->newest_pathname = ti->pathname;
1057 } else if (ti->pathname2[0] == '\0') {
1058 strncpy(ti->pathname2, pathname, MAXPATHLEN);
1059 ti->newest_pathname = ti->pathname2;
1060 }
1061 }
1062 }
1063 }
1064
1065 break;
1066 }
1067
1068 if (type != Throttled && type != HFS_update)
1069 return;
1070
1071 if (event->debugid & DBG_FUNC_START) {
1072 event_enter(type, event);
1073 } else {
1074 switch (type) {
1075 case Throttled:
1076 event_exit(" THROTTLED", type, event, FMT_NOTHING);
1077 break;
1078
1079 case HFS_update:
1080 event_exit(" HFS_update", type, event, FMT_HFS_update);
1081 break;
1082
1083 default:
1084 abort();
1085 }
1086 }
1087 });
1088
1089 ktrace_events_subclass(s, DBG_FSYSTEM, DBG_DKRW, ^(ktrace_event_t event) {
1090 struct diskio *dio;
1091 unsigned int type;
1092
1093 type = event->debugid & KDBG_EVENTID_MASK;
1094
1095 if ((type & P_DISKIO_MASK) == P_DISKIO) {
1096 diskio_start(type, event->arg1, event->arg2, event->arg3, event->arg4, event);
1097 } else if ((type & P_DISKIO_MASK) == P_DISKIO_DONE) {
1098 if ((dio = diskio_complete(event->arg1, event->arg4, event->arg3, event->threadid, event->timestamp, event->walltime))) {
1099 dio->vnodeid = event->arg2;
1100 diskio_print(dio);
1101 diskio_free(dio);
1102 }
1103 }
1104 });
1105
1106 ktrace_events_subclass(s, DBG_FSYSTEM, DBG_IOCTL, ^(ktrace_event_t event) {
1107 th_info_t ti;
1108 int type;
1109 pid_t pid;
1110
1111 type = event->debugid & KDBG_EVENTID_MASK;
1112
1113 switch (type) {
1114 case SPEC_unmap_info:
1115 pid = ktrace_get_pid_for_thread(s, event->threadid);
1116
1117 if (check_filter_mode(pid, NULL, SPEC_unmap_info, 0, 0, "SPEC_unmap_info"))
1118 format_print(NULL, " TrimExtent", event, type, FMT_UNMAP_INFO, event->timestamp, event->timestamp, 0, "", NULL);
1119
1120 break;
1121
1122 case SPEC_ioctl:
1123 if (event->debugid & DBG_FUNC_START) {
1124 event_enter(type, event);
1125 } else {
1126 if (event->arg2 == DKIOCSYNCHRONIZECACHE)
1127 event_exit("IOCTL", type, event, FMT_IOCTL_SYNCCACHE);
1128 else if (event->arg2 == DKIOCUNMAP)
1129 event_exit("IOCTL", type, event, FMT_IOCTL_UNMAP);
1130 else if (event->arg2 == DKIOCSYNCHRONIZE && (event->debugid & DBG_FUNC_ALL) == DBG_FUNC_NONE)
1131 event_exit("IOCTL", type, event, FMT_IOCTL_SYNC);
1132 else if ((ti = event_find(event->threadid, type)))
1133 event_delete(ti);
1134 }
1135
1136 break;
1137 }
1138 });
1139
1140 if (BC_flag || RAW_flag) {
1141 ktrace_events_subclass(s, DBG_FSYSTEM, DBG_BOOTCACHE, ^(ktrace_event_t event) {
1142 struct diskio *dio;
1143 unsigned int type;
1144
1145 type = event->debugid & KDBG_EVENTID_MASK;
1146
1147 switch (type) {
1148 case BC_IO_HIT:
1149 case BC_IO_HIT_STALLED:
1150 case BC_IO_MISS:
1151 case BC_IO_MISS_CUT_THROUGH:
1152 case BC_PLAYBACK_IO:
1153 if ((dio = diskio_find(event->arg1)) != NULL)
1154 dio->bc_info = type;
1155 }
1156 });
1157 }
1158
1159 void (^bsd_sc_proc_cb)(ktrace_event_t event) = ^(ktrace_event_t event) {
1160 int type, index;
1161 pid_t pid;
1162
1163 type = event->debugid & KDBG_EVENTID_MASK;
1164
1165 switch (type) {
1166 case BSC_exit: /* see below */
1167 return;
1168
1169 case proc_exit:
1170 event->arg1 = event->arg2 >> 8;
1171 type = BSC_exit;
1172
1173 pid = ktrace_get_pid_for_thread(s, event->threadid);
1174 fd_clear_pid(pid);
1175
1176 break;
1177
1178 case BSC_mmap:
1179 if (event->arg4 & MAP_ANON)
1180 return;
1181
1182 break;
1183 }
1184
1185 if ((index = BSC_INDEX(type)) >= MAX_BSD_SYSCALL)
1186 return;
1187
1188 if (!bsd_syscalls[index].sc_name)
1189 return;
1190
1191 if (event->debugid & DBG_FUNC_START) {
1192 event_enter(type, event);
1193 } else {
1194 event_exit(bsd_syscalls[index].sc_name, type, event, bsd_syscalls[index].sc_format);
1195 }
1196 };
1197
1198 ktrace_events_subclass(s, DBG_BSD, DBG_BSD_EXCP_SC, bsd_sc_proc_cb);
1199 ktrace_events_subclass(s, DBG_BSD, DBG_BSD_PROC, bsd_sc_proc_cb);
1200
1201 ktrace_events_range(s, KDBG_EVENTID(DBG_BSD, DBG_BSD_SC_EXTENDED_INFO, 0), KDBG_EVENTID(DBG_BSD, DBG_BSD_SC_EXTENDED_INFO2 + 1, 0), ^(ktrace_event_t event) {
1202 extend_syscall(event->threadid, event->debugid & KDBG_EVENTID_MASK, event);
1203 });
1204
1205 ktrace_events_subclass(s, DBG_CORESTORAGE, DBG_CS_IO, ^(ktrace_event_t event) {
1206 // the usual DBG_FUNC_START/END does not work for i/o since it will
1207 // return on a different thread, this code uses the P_CS_IO_Done (0x4) bit
1208 // instead. the trace command doesn't know how handle either method
1209 // (unmatched start/end or 0x4) but works a little better this way.
1210
1211 struct diskio *dio;
1212 int cs_type = event->debugid & P_CS_Type_Mask; // strip out the done bit
1213 bool start = (event->debugid & P_CS_IO_Done) != P_CS_IO_Done;
1214
1215 switch (cs_type) {
1216 case P_CS_ReadChunk:
1217 case P_CS_WriteChunk:
1218 case P_CS_MetaRead:
1219 case P_CS_MetaWrite:
1220 if (start) {
1221 diskio_start(cs_type, event->arg2, event->arg1, event->arg3, event->arg4, event);
1222 } else {
1223 if ((dio = diskio_complete(event->arg2, event->arg4, event->arg3, event->threadid, event->timestamp, event->walltime))) {
1224 diskio_print(dio);
1225 diskio_free(dio);
1226 }
1227 }
1228
1229 break;
1230 case P_CS_TransformRead:
1231 case P_CS_TransformWrite:
1232 case P_CS_MigrationRead:
1233 case P_CS_MigrationWrite:
1234 if (start) {
1235 diskio_start(cs_type, event->arg2, CS_DEV, event->arg3, event->arg4, event);
1236 } else {
1237 if ((dio = diskio_complete(event->arg2, event->arg4, event->arg3, event->threadid, event->timestamp, event->walltime))) {
1238 diskio_print(dio);
1239 diskio_free(dio);
1240 }
1241 }
1242
1243 break;
1244 }
1245 });
1246
1247 ktrace_events_subclass(s, DBG_CORESTORAGE, 1 /* DBG_CS_SYNC */, ^(ktrace_event_t event) {
1248 int cs_type = event->debugid & P_CS_Type_Mask; // strip out the done bit
1249 bool start = (event->debugid & P_CS_IO_Done) != P_CS_IO_Done;
1250
1251 if (cs_type == P_CS_SYNC_DISK) {
1252 if (start) {
1253 event_enter(cs_type, event);
1254 } else {
1255 event_exit(" SyncCacheCS", cs_type, event, FMT_SYNC_DISK_CS);
1256 }
1257 }
1258 });
1259 }
1260
1261 /*
1262 * Handle system call extended trace data.
1263 * pread and pwrite:
1264 * Wipe out the kd args that were collected upon syscall_entry
1265 * because it is the extended info that we really want, and it
1266 * is all we really need.
1267 */
1268 void
1269 extend_syscall(uintptr_t thread, int type, ktrace_event_t event)
1270 {
1271 th_info_t ti;
1272
1273 switch (type) {
1274 case BSC_mmap_extended:
1275 if ((ti = event_find(thread, BSC_mmap)) == NULL)
1276 return;
1277
1278 ti->arg8 = ti->arg3; /* save protection */
1279 ti->arg1 = event->arg1; /* the fd */
1280 ti->arg3 = event->arg2; /* bottom half address */
1281 ti->arg5 = event->arg3; /* bottom half size */
1282 break;
1283
1284 case BSC_mmap_extended2:
1285 if ((ti = event_find(thread, BSC_mmap)) == NULL)
1286 return;
1287
1288 ti->arg2 = event->arg1; /* top half address */
1289 ti->arg4 = event->arg2; /* top half size */
1290 ti->arg6 = event->arg3; /* top half file offset */
1291 ti->arg7 = event->arg4; /* bottom half file offset */
1292 break;
1293
1294 case BSC_msync_extended:
1295 if ((ti = event_find(thread, BSC_msync)) == NULL) {
1296 if ((ti = event_find(thread, BSC_msync_nocancel)) == NULL)
1297 return;
1298 }
1299
1300 ti->arg4 = event->arg1; /* top half address */
1301 ti->arg5 = event->arg2; /* top half size */
1302 break;
1303
1304 case BSC_pread_extended:
1305 if ((ti = event_find(thread, BSC_pread)) == NULL) {
1306 if ((ti = event_find(thread, BSC_pread_nocancel)) == NULL)
1307 return;
1308 }
1309
1310 ti->arg1 = event->arg1; /* the fd */
1311 ti->arg2 = event->arg2; /* nbytes */
1312 ti->arg3 = event->arg3; /* top half offset */
1313 ti->arg4 = event->arg4; /* bottom half offset */
1314 break;
1315
1316 case BSC_pwrite_extended:
1317 if ((ti = event_find(thread, BSC_pwrite)) == NULL) {
1318 if ((ti = event_find(thread, BSC_pwrite_nocancel)) == NULL)
1319 return;
1320 }
1321
1322 ti->arg1 = event->arg1; /* the fd */
1323 ti->arg2 = event->arg2; /* nbytes */
1324 ti->arg3 = event->arg3; /* top half offset */
1325 ti->arg4 = event->arg4; /* bottom half offset */
1326 break;
1327 }
1328 }
1329
1330 #pragma mark printing routines
1331
1332 static void
1333 get_mode_nibble(char *buf, unsigned long smode, unsigned long special, char x_on, char x_off)
1334 {
1335 if (smode & 04)
1336 buf[0] = 'r';
1337
1338 if (smode & 02)
1339 buf[1] = 'w';
1340
1341 if (smode & 01) {
1342 if (special)
1343 buf[2] = x_on;
1344 else
1345 buf[2] = 'x';
1346 } else {
1347 if (special)
1348 buf[2] = x_off;
1349 }
1350 }
1351
1352 static void
1353 get_mode_string(unsigned long mode, char *buf)
1354 {
1355 memset(buf, '-', 9);
1356 buf[9] = '\0';
1357
1358 get_mode_nibble(&buf[6], mode, (mode & 01000), 't', 'T');
1359 get_mode_nibble(&buf[3], (mode>>3), (mode & 02000), 's', 'S');
1360 get_mode_nibble(&buf[0], (mode>>6), (mode & 04000), 's', 'S');
1361 }
1362
1363 static int
1364 clip_64bit(char *s, uint64_t value)
1365 {
1366 int clen = 0;
1367
1368 if ( (value & 0xff00000000000000LL) )
1369 clen = printf("%s0x%16.16qx", s, value);
1370 else if ( (value & 0x00ff000000000000LL) )
1371 clen = printf("%s0x%14.14qx ", s, value);
1372 else if ( (value & 0x0000ff0000000000LL) )
1373 clen = printf("%s0x%12.12qx ", s, value);
1374 else if ( (value & 0x000000ff00000000LL) )
1375 clen = printf("%s0x%10.10qx ", s, value);
1376 else
1377 clen = printf("%s0x%8.8qx ", s, value);
1378
1379 return clen;
1380 }
1381
1382 /*
1383 * ret = 1 means print the entry
1384 * ret = 0 means don't print the entry
1385 */
1386
1387 /*
1388 * meaning of filter flags:
1389 * cachehit turn on display of CACHE_HIT events (which are filtered out by default)
1390 *
1391 * exec show exec/posix_spawn
1392 * pathname show events with a pathname and close()
1393 * diskio show disk I/Os
1394 * filesys show filesystem events
1395 * network show network events
1396 *
1397 * filters may be combined; default is all filters on (except cachehit)
1398 */
1399 bool
1400 check_filter_mode(pid_t pid, th_info_t ti, unsigned long type, int error, int retval, char *sc_name)
1401 {
1402 bool ret = false;
1403 int network_fd_isset = 0;
1404 unsigned long fd;
1405
1406 /* cachehit is special -- it's not on by default */
1407 if (sc_name[0] == 'C' && !strcmp(sc_name, "CACHE_HIT")) {
1408 return show_cachehits;
1409 }
1410
1411 if (filter_mode == DEFAULT_DO_NOT_FILTER)
1412 return true;
1413
1414 if (filter_mode & DISKIO_FILTER) {
1415 if ((type & P_DISKIO_MASK) == P_DISKIO)
1416 return true;
1417
1418 if (type == Throttled)
1419 return true;
1420 }
1421
1422 if (filter_mode & EXEC_FILTER) {
1423 if (type == BSC_execve || type == BSC_posix_spawn)
1424 return true;
1425 }
1426
1427 if (filter_mode & PATHNAME_FILTER) {
1428 if (ti && ti->pathname[0])
1429 return true;
1430
1431 if (type == BSC_close || type == BSC_close_nocancel ||
1432 type == BSC_guarded_close_np)
1433 return true;
1434 }
1435
1436 if (!ti) {
1437 if (filter_mode & FILESYS_FILTER)
1438 return true;
1439
1440 return 0;
1441 }
1442
1443 switch (type) {
1444 case BSC_close:
1445 case BSC_close_nocancel:
1446 case BSC_guarded_close_np:
1447 fd = ti->arg1;
1448 network_fd_isset = fd_is_network(pid, fd);
1449
1450 if (error == 0)
1451 fd_set_is_network(pid, fd, false);
1452
1453 if (network_fd_isset) {
1454 if (filter_mode & NETWORK_FILTER)
1455 ret = true;
1456 } else {
1457 if (filter_mode & FILESYS_FILTER)
1458 ret = true;
1459 }
1460
1461 break;
1462
1463 case BSC_read:
1464 case BSC_write:
1465 case BSC_read_nocancel:
1466 case BSC_write_nocancel:
1467 /*
1468 * we don't care about error in these cases
1469 */
1470 fd = ti->arg1;
1471
1472 if (fd_is_network(pid, fd)) {
1473 if (filter_mode & NETWORK_FILTER)
1474 ret = true;
1475 } else if (filter_mode & FILESYS_FILTER) {
1476 ret = true;
1477 }
1478
1479 break;
1480
1481 case BSC_accept:
1482 case BSC_accept_nocancel:
1483 case BSC_socket:
1484 fd = retval;
1485
1486 if (error == 0)
1487 fd_set_is_network(pid, fd, true);
1488
1489 if (filter_mode & NETWORK_FILTER)
1490 ret = true;
1491
1492 break;
1493
1494 case BSC_recvfrom:
1495 case BSC_sendto:
1496 case BSC_recvmsg:
1497 case BSC_sendmsg:
1498 case BSC_connect:
1499 case BSC_bind:
1500 case BSC_listen:
1501 case BSC_sendto_nocancel:
1502 case BSC_recvfrom_nocancel:
1503 case BSC_recvmsg_nocancel:
1504 case BSC_sendmsg_nocancel:
1505 case BSC_connect_nocancel:
1506 fd = ti->arg1;
1507
1508 if (error == 0)
1509 fd_set_is_network(pid, fd, true);
1510
1511 if (filter_mode & NETWORK_FILTER)
1512 ret = true;
1513
1514 break;
1515
1516 case BSC_select:
1517 case BSC_select_nocancel:
1518 case BSC_socketpair:
1519 /*
1520 * Cannot determine info about file descriptors
1521 */
1522 if (filter_mode & NETWORK_FILTER)
1523 ret = true;
1524
1525 break;
1526
1527 case BSC_dup:
1528 case BSC_dup2:
1529 /*
1530 * We track these cases for fd state only
1531 */
1532 fd = ti->arg1;
1533
1534 if (error == 0 && fd_is_network(pid, fd)) {
1535 /*
1536 * then we are duping a socket descriptor
1537 */
1538 fd = retval; /* the new fd */
1539 fd_set_is_network(pid, fd, true);
1540 }
1541
1542 break;
1543
1544 default:
1545 if (filter_mode & FILESYS_FILTER)
1546 ret = true;
1547
1548 break;
1549 }
1550
1551 return ret;
1552 }
1553
1554 /*
1555 * called from:
1556 *
1557 * exit_event() (syscalls etc.)
1558 * print_diskio() (disk I/Os)
1559 * block callback for TrimExtent
1560 */
1561 void
1562 format_print(th_info_t ti, char *sc_name, ktrace_event_t event,
1563 unsigned long type, int format, uint64_t now, uint64_t stime,
1564 int waited, const char *pathname, struct diskio *dio)
1565 {
1566 uint64_t secs, usecs;
1567 int nopadding = 0;
1568 static time_t last_walltime_secs = -1;
1569 const char *command_name;
1570 pid_t pid;
1571 int len = 0;
1572 int clen = 0;
1573 size_t tlen = 0;
1574 unsigned long class;
1575 uint64_t user_addr;
1576 uint64_t user_size;
1577 char *framework_name;
1578 char *framework_type;
1579 char *p1;
1580 char *p2;
1581 char buf[MAXWIDTH];
1582 char cs_diskname[32];
1583 unsigned long threadid;
1584 struct timeval now_walltime;
1585
1586 static char timestamp[32];
1587 static size_t timestamp_len = 0;
1588
1589 if (!mach_time_of_first_event)
1590 mach_time_of_first_event = now;
1591
1592 if (format == FMT_DISKIO || format == FMT_DISKIO_CS) {
1593 assert(dio);
1594 } else {
1595 assert(event);
1596
1597 if (format != FMT_UNMAP_INFO)
1598 assert(ti);
1599 }
1600
1601 /* <rdar://problem/19852325> Filter out WindowServer/xcpm ioctls in fs_usage */
1602 if (type == BSC_ioctl && ti->arg2 == 0xffffffffc030581dUL)
1603 return;
1604
1605 /* honor -S and -E */
1606 if (RAW_flag) {
1607 uint64_t relative_time_ns;
1608
1609 relative_time_ns = mach_to_nano(now - mach_time_of_first_event);
1610
1611 if (relative_time_ns < start_time_ns || relative_time_ns > end_time_ns)
1612 return;
1613 }
1614
1615 class = KDBG_EXTRACT_CLASS(type);
1616
1617 if (dio) {
1618 command_name = dio->issuing_command;
1619 threadid = dio->issuing_thread;
1620 pid = dio->issuing_pid;
1621 now_walltime = dio->completed_walltime;
1622 } else {
1623 if (ti && ti->command[0] != '\0') {
1624 command_name = ti->command;
1625 threadid = ti->thread;
1626 pid = ti->pid;
1627 } else {
1628 command_name = ktrace_get_execname_for_thread(s, event->threadid);
1629 threadid = event->threadid;
1630 pid = ktrace_get_pid_for_thread(s, event->threadid);
1631 }
1632
1633 now_walltime = event->walltime;
1634 }
1635
1636 if (!want_kernel_task && pid == 0)
1637 return;
1638
1639 if (!command_name)
1640 command_name = "";
1641
1642 assert(now_walltime.tv_sec || now_walltime.tv_usec);
1643
1644 /* try and reuse the timestamp string */
1645 if (last_walltime_secs != now_walltime.tv_sec) {
1646 timestamp_len = strftime(timestamp, sizeof (timestamp), "%H:%M:%S", localtime(&now_walltime.tv_sec));
1647 last_walltime_secs = now_walltime.tv_sec;
1648 }
1649
1650 if (columns > MAXCOLS || wideflag) {
1651 tlen = timestamp_len;
1652 nopadding = 0;
1653
1654 sprintf(&timestamp[tlen], ".%06d", now_walltime.tv_usec);
1655 tlen += 7;
1656
1657 timestamp[tlen] = '\0';
1658 } else {
1659 nopadding = 1;
1660 }
1661
1662 clen = printf("%s %-17.17s", timestamp, sc_name);
1663
1664 framework_name = NULL;
1665
1666 if (columns > MAXCOLS || wideflag) {
1667 off_t offset_reassembled = 0LL;
1668
1669 switch (format) {
1670 case FMT_NOTHING:
1671 clen += printf(" ");
1672 break;
1673
1674 case FMT_AT:
1675 case FMT_RENAMEAT:
1676 case FMT_DEFAULT:
1677 /*
1678 * pathname based system calls or
1679 * calls with no fd or pathname (i.e. sync)
1680 */
1681 if (event->arg1)
1682 clen += printf(" [%3d] ", (int)event->arg1);
1683 else
1684 clen += printf(" ");
1685
1686 break;
1687
1688 case FMT_FD:
1689 /*
1690 * fd based system call... no I/O
1691 */
1692 if (event->arg1)
1693 clen += printf(" F=%-3d[%3d]", (int)ti->arg1, (int)event->arg1);
1694 else
1695 clen += printf(" F=%-3d", (int)ti->arg1);
1696
1697 break;
1698
1699 case FMT_FD_2:
1700 /*
1701 * accept, dup, dup2
1702 */
1703 if (event->arg1)
1704 clen += printf(" F=%-3d[%3d]", (int)ti->arg1, (int)event->arg1);
1705 else
1706 clen += printf(" F=%-3d F=%-3d", (int)ti->arg1, (int)event->arg2);
1707
1708 break;
1709
1710 case FMT_FD_IO:
1711 /*
1712 * system calls with fd's that return an I/O completion count
1713 */
1714 if (event->arg1)
1715 clen += printf(" F=%-3d[%3d]", (int)ti->arg1, (int)event->arg1);
1716 else
1717 clen += printf(" F=%-3d B=0x%-6lx", (int)ti->arg1, event->arg2);
1718
1719 break;
1720
1721 case FMT_PGIN:
1722 /*
1723 * pagein
1724 */
1725 user_addr = ((uint64_t)event->arg1 << 32) | (uint32_t)event->arg2;
1726
1727 lookup_name(user_addr, &framework_type, &framework_name);
1728 clen += clip_64bit(" A=", user_addr);
1729 break;
1730
1731 case FMT_CACHEHIT:
1732 /*
1733 * cache hit
1734 */
1735 user_addr = ((uint64_t)event->arg1 << 32) | (uint32_t)event->arg2;
1736
1737 lookup_name(user_addr, &framework_type, &framework_name);
1738 clen += clip_64bit(" A=", user_addr);
1739 break;
1740
1741 case FMT_PGOUT:
1742 /*
1743 * pageout
1744 */
1745 clen += printf(" B=0x%-8lx", event->arg1);
1746 break;
1747
1748 case FMT_HFS_update:
1749 {
1750 static const struct {
1751 int flag;
1752 char ch;
1753 } hfsflags[] = {
1754 { DBG_HFS_UPDATE_SKIPPED, 'S' },
1755 { DBG_HFS_UPDATE_FORCE, 'F' },
1756 { DBG_HFS_UPDATE_MODIFIED, 'M' },
1757 { DBG_HFS_UPDATE_MINOR, 'N' },
1758 { DBG_HFS_UPDATE_DATEADDED, 'd' },
1759 { DBG_HFS_UPDATE_CHGTIME, 'c' },
1760 { DBG_HFS_UPDATE_ACCTIME, 'a' },
1761 { DBG_HFS_UPDATE_MODTIME, 'm' },
1762 };
1763 size_t i;
1764 int flagcount;
1765 char *sbuf;
1766 int sflag = (int)event->arg2;
1767
1768 flagcount = sizeof (hfsflags) / sizeof (*hfsflags);
1769 sbuf = malloc(flagcount + 1);
1770
1771 for (i = 0; i < flagcount; i++) {
1772 if (sflag & hfsflags[i].flag) {
1773 sbuf[i] = hfsflags[i].ch;
1774 } else {
1775 sbuf[i] = '_';
1776 }
1777 }
1778
1779 sbuf[flagcount] = '\0';
1780
1781 clen += printf(" %*s(%s) ", 17 - flagcount, "", sbuf);
1782
1783 free(sbuf);
1784
1785 pathname = ktrace_get_path_for_vp(s, event->arg1);
1786
1787 if (!pathname)
1788 pathname = "";
1789
1790 nopadding = 1;
1791
1792 break;
1793 }
1794
1795 case FMT_DISKIO:
1796 /*
1797 * physical disk I/O
1798 */
1799 if (dio->io_errno) {
1800 clen += printf(" D=0x%8.8lx [%3d]", dio->blkno, (int)dio->io_errno);
1801 } else {
1802 if (BC_flag)
1803 clen += printf(" D=0x%8.8lx B=0x%-6lx BC:%s /dev/%s ", dio->blkno, dio->iosize, BC_STR(dio->bc_info), find_disk_name(dio->dev));
1804 else
1805 clen += printf(" D=0x%8.8lx B=0x%-6lx /dev/%s ", dio->blkno, dio->iosize, find_disk_name(dio->dev));
1806
1807 if (dio->is_meta) {
1808 if (!(type & P_DISKIO_READ)) {
1809 pathname = meta_find_name(dio->blkno);
1810 }
1811 } else {
1812 pathname = ktrace_get_path_for_vp(s, dio->vnodeid);
1813
1814 if (!pathname)
1815 pathname = "";
1816 }
1817
1818 nopadding = 1;
1819 }
1820
1821 break;
1822
1823 case FMT_DISKIO_CS:
1824 /*
1825 * physical disk I/O
1826 */
1827 if (dio->io_errno)
1828 clen += printf(" D=0x%8.8lx [%3lu]", dio->blkno, dio->io_errno);
1829 else
1830 clen += printf(" D=0x%8.8lx B=0x%-6lx /dev/%s", dio->blkno, dio->iosize, generate_cs_disk_name(dio->dev, cs_diskname));
1831
1832 break;
1833
1834 case FMT_SYNC_DISK_CS:
1835 /*
1836 * physical disk sync cache
1837 */
1838 clen += printf(" /dev/%s", generate_cs_disk_name(event->arg1, cs_diskname));
1839
1840 break;
1841
1842 case FMT_MSYNC:
1843 {
1844 /*
1845 * msync
1846 */
1847 int mlen = 0;
1848
1849 buf[0] = '\0';
1850
1851 if (ti->arg3 & MS_ASYNC)
1852 mlen += sprintf(&buf[mlen], "MS_ASYNC | ");
1853 else
1854 mlen += sprintf(&buf[mlen], "MS_SYNC | ");
1855
1856 if (ti->arg3 & MS_INVALIDATE)
1857 mlen += sprintf(&buf[mlen], "MS_INVALIDATE | ");
1858 if (ti->arg3 & MS_KILLPAGES)
1859 mlen += sprintf(&buf[mlen], "MS_KILLPAGES | ");
1860 if (ti->arg3 & MS_DEACTIVATE)
1861 mlen += sprintf(&buf[mlen], "MS_DEACTIVATE | ");
1862
1863 if (ti->arg3 & ~(MS_ASYNC | MS_SYNC | MS_INVALIDATE | MS_KILLPAGES | MS_DEACTIVATE))
1864 mlen += sprintf(&buf[mlen], "UNKNOWN | ");
1865
1866 if (mlen)
1867 buf[mlen - 3] = '\0';
1868
1869 if (event->arg1)
1870 clen += printf(" [%3d]", (int)event->arg1);
1871
1872 user_addr = (((off_t)(unsigned int)(ti->arg4)) << 32) | (unsigned int)(ti->arg1);
1873 clen += clip_64bit(" A=", user_addr);
1874
1875 user_size = (((off_t)(unsigned int)(ti->arg5)) << 32) | (unsigned int)(ti->arg2);
1876
1877 clen += printf(" B=0x%-16qx <%s>", user_size, buf);
1878
1879 break;
1880 }
1881
1882 case FMT_FLOCK:
1883 {
1884 /*
1885 * flock
1886 */
1887 int mlen = 0;
1888
1889 buf[0] = '\0';
1890
1891 if (ti->arg2 & LOCK_SH)
1892 mlen += sprintf(&buf[mlen], "LOCK_SH | ");
1893 if (ti->arg2 & LOCK_EX)
1894 mlen += sprintf(&buf[mlen], "LOCK_EX | ");
1895 if (ti->arg2 & LOCK_NB)
1896 mlen += sprintf(&buf[mlen], "LOCK_NB | ");
1897 if (ti->arg2 & LOCK_UN)
1898 mlen += sprintf(&buf[mlen], "LOCK_UN | ");
1899
1900 if (ti->arg2 & ~(LOCK_SH | LOCK_EX | LOCK_NB | LOCK_UN))
1901 mlen += sprintf(&buf[mlen], "UNKNOWN | ");
1902
1903 if (mlen)
1904 buf[mlen - 3] = '\0';
1905
1906 if (event->arg1)
1907 clen += printf(" F=%-3d[%3d] <%s>", (int)ti->arg1, (int)event->arg1, buf);
1908 else
1909 clen += printf(" F=%-3d <%s>", (int)ti->arg1, buf);
1910
1911 break;
1912 }
1913
1914 case FMT_FCNTL:
1915 {
1916 /*
1917 * fcntl
1918 */
1919 char *p = NULL;
1920 int fd = -1;
1921
1922 if (event->arg1)
1923 clen += printf(" F=%-3d[%3d]", (int)ti->arg1, (int)event->arg1);
1924 else
1925 clen += printf(" F=%-3d", (int)ti->arg1);
1926
1927 switch(ti->arg2) {
1928 case F_DUPFD:
1929 p = "DUPFD";
1930 break;
1931
1932 case F_GETFD:
1933 p = "GETFD";
1934 break;
1935
1936 case F_SETFD:
1937 p = "SETFD";
1938 break;
1939
1940 case F_GETFL:
1941 p = "GETFL";
1942 break;
1943
1944 case F_SETFL:
1945 p = "SETFL";
1946 break;
1947
1948 case F_GETOWN:
1949 p = "GETOWN";
1950 break;
1951
1952 case F_SETOWN:
1953 p = "SETOWN";
1954 break;
1955
1956 case F_GETLK:
1957 p = "GETLK";
1958 break;
1959
1960 case F_SETLK:
1961 p = "SETLK";
1962 break;
1963
1964 case F_SETLKW:
1965 p = "SETLKW";
1966 break;
1967
1968 case F_PREALLOCATE:
1969 p = "PREALLOCATE";
1970 break;
1971
1972 case F_SETSIZE:
1973 p = "SETSIZE";
1974 break;
1975
1976 case F_RDADVISE:
1977 p = "RDADVISE";
1978 break;
1979
1980 case F_GETPATH:
1981 p = "GETPATH";
1982 break;
1983
1984 case F_FULLFSYNC:
1985 p = "FULLFSYNC";
1986 break;
1987
1988 case F_PATHPKG_CHECK:
1989 p = "PATHPKG_CHECK";
1990 break;
1991
1992 case F_OPENFROM:
1993 p = "OPENFROM";
1994
1995 if (event->arg1 == 0)
1996 fd = (int)event->arg2;
1997 break;
1998
1999 case F_UNLINKFROM:
2000 p = "UNLINKFROM";
2001 break;
2002
2003 case F_CHECK_OPENEVT:
2004 p = "CHECK_OPENEVT";
2005 break;
2006
2007 case F_NOCACHE:
2008 if (ti->arg3)
2009 p = "CACHING OFF";
2010 else
2011 p = "CACHING ON";
2012 break;
2013
2014 case F_GLOBAL_NOCACHE:
2015 if (ti->arg3)
2016 p = "CACHING OFF (GLOBAL)";
2017 else
2018 p = "CACHING ON (GLOBAL)";
2019 break;
2020
2021 }
2022
2023 if (p) {
2024 if (fd == -1)
2025 clen += printf(" <%s>", p);
2026 else
2027 clen += printf(" <%s> F=%d", p, fd);
2028 } else {
2029 clen += printf(" <CMD=%d>", (int)ti->arg2);
2030 }
2031
2032 break;
2033 }
2034
2035 case FMT_IOCTL:
2036 {
2037 /*
2038 * ioctl
2039 */
2040 if (event->arg1)
2041 clen += printf(" F=%-3d[%3d]", (int)ti->arg1, (int)event->arg1);
2042 else
2043 clen += printf(" F=%-3d", (int)ti->arg1);
2044
2045 clen += printf(" <CMD=0x%x>", (int)ti->arg2);
2046
2047 break;
2048 }
2049
2050 case FMT_IOCTL_SYNC:
2051 {
2052 /*
2053 * ioctl
2054 */
2055 clen += printf(" <DKIOCSYNCHRONIZE> B=%lu /dev/%s", event->arg3, find_disk_name(event->arg1));
2056
2057 break;
2058 }
2059
2060 case FMT_IOCTL_SYNCCACHE:
2061 {
2062 /*
2063 * ioctl
2064 */
2065 clen += printf(" <DKIOCSYNCHRONIZECACHE> /dev/%s", find_disk_name(event->arg1));
2066
2067 break;
2068 }
2069
2070 case FMT_IOCTL_UNMAP:
2071 {
2072 /*
2073 * ioctl
2074 */
2075 clen += printf(" <DKIOCUNMAP> /dev/%s", find_disk_name(event->arg1));
2076
2077 break;
2078 }
2079
2080 case FMT_UNMAP_INFO:
2081 {
2082 clen += printf(" D=0x%8.8lx B=0x%-6lx /dev/%s", event->arg2, event->arg3, find_disk_name(event->arg1));
2083
2084 break;
2085 }
2086
2087 case FMT_SELECT:
2088 /*
2089 * select
2090 */
2091 if (event->arg1)
2092 clen += printf(" [%3d]", (int)event->arg1);
2093 else
2094 clen += printf(" S=%-3d", (int)event->arg2);
2095
2096 break;
2097
2098 case FMT_LSEEK:
2099 case FMT_PREAD:
2100 /*
2101 * pread, pwrite, lseek
2102 */
2103 clen += printf(" F=%-3d", (int)ti->arg1);
2104
2105 if (event->arg1) {
2106 clen += printf("[%3d] ", (int)event->arg1);
2107 } else {
2108 if (format == FMT_PREAD)
2109 clen += printf(" B=0x%-8lx ", event->arg2);
2110 else
2111 clen += printf(" ");
2112 }
2113
2114 if (format == FMT_PREAD)
2115 offset_reassembled = (((off_t)(unsigned int)(ti->arg3)) << 32) | (unsigned int)(ti->arg4);
2116 else
2117 #ifdef __ppc__
2118 offset_reassembled = (((off_t)(unsigned int)(arg2)) << 32) | (unsigned int)(arg3);
2119 #else
2120 offset_reassembled = (((off_t)(unsigned int)(event->arg3)) << 32) | (unsigned int)(event->arg2);
2121 #endif
2122
2123 clen += clip_64bit("O=", offset_reassembled);
2124
2125 if (format == FMT_LSEEK) {
2126 char *mode;
2127
2128 if (ti->arg3 == SEEK_SET)
2129 mode = "SEEK_SET";
2130 else if (ti->arg3 == SEEK_CUR)
2131 mode = "SEEK_CUR";
2132 else if (ti->arg3 == SEEK_END)
2133 mode = "SEEK_END";
2134 else
2135 mode = "UNKNOWN";
2136
2137 clen += printf(" <%s>", mode);
2138 }
2139
2140 break;
2141
2142 case FMT_MMAP:
2143 /*
2144 * mmap
2145 */
2146 clen += printf(" F=%-3d ", (int)ti->arg1);
2147
2148 if (event->arg1) {
2149 clen += printf("[%3d] ", (int)event->arg1);
2150 } else {
2151 user_addr = (((off_t)(unsigned int)(ti->arg2)) << 32) | (unsigned int)(ti->arg3);
2152
2153 clen += clip_64bit("A=", user_addr);
2154
2155 offset_reassembled = (((off_t)(unsigned int)(ti->arg6)) << 32) | (unsigned int)(ti->arg7);
2156
2157 clen += clip_64bit("O=", offset_reassembled);
2158
2159 user_size = (((off_t)(unsigned int)(ti->arg4)) << 32) | (unsigned int)(ti->arg5);
2160
2161 clen += printf("B=0x%-16qx", user_size);
2162
2163 clen += printf(" <");
2164
2165 if (ti->arg8 & PROT_READ)
2166 clen += printf("READ");
2167
2168 if (ti->arg8 & PROT_WRITE)
2169 clen += printf("|WRITE");
2170
2171 if (ti->arg8 & PROT_EXEC)
2172 clen += printf("|EXEC");
2173
2174 clen += printf(">");
2175 }
2176
2177 break;
2178
2179 case FMT_TRUNC:
2180 case FMT_FTRUNC:
2181 /*
2182 * ftruncate, truncate
2183 */
2184 if (format == FMT_FTRUNC)
2185 clen += printf(" F=%-3d", (int)ti->arg1);
2186 else
2187 clen += printf(" ");
2188
2189 if (event->arg1)
2190 clen += printf("[%3d]", (int)event->arg1);
2191
2192 #ifdef __ppc__
2193 offset_reassembled = (((off_t)(unsigned int)(ti->arg2)) << 32) | (unsigned int)(ti->arg3);
2194 #else
2195 offset_reassembled = (((off_t)(unsigned int)(ti->arg3)) << 32) | (unsigned int)(ti->arg2);
2196 #endif
2197 clen += clip_64bit(" O=", offset_reassembled);
2198
2199 nopadding = 1;
2200 break;
2201
2202 case FMT_FCHFLAGS:
2203 case FMT_CHFLAGS:
2204 {
2205 /*
2206 * fchflags, chflags
2207 */
2208 int mlen = 0;
2209
2210 if (format == FMT_FCHFLAGS) {
2211 if (event->arg1)
2212 clen += printf(" F=%-3d[%3d]", (int)ti->arg1, (int)event->arg1);
2213 else
2214 clen += printf(" F=%-3d", (int)ti->arg1);
2215 } else {
2216 if (event->arg1)
2217 clen += printf(" [%3d] ", (int)event->arg1);
2218 }
2219
2220 buf[mlen++] = ' ';
2221 buf[mlen++] = '<';
2222
2223 if (ti->arg2 & UF_NODUMP)
2224 mlen += sprintf(&buf[mlen], "UF_NODUMP | ");
2225 if (ti->arg2 & UF_IMMUTABLE)
2226 mlen += sprintf(&buf[mlen], "UF_IMMUTABLE | ");
2227 if (ti->arg2 & UF_APPEND)
2228 mlen += sprintf(&buf[mlen], "UF_APPEND | ");
2229 if (ti->arg2 & UF_OPAQUE)
2230 mlen += sprintf(&buf[mlen], "UF_OPAQUE | ");
2231 if (ti->arg2 & SF_ARCHIVED)
2232 mlen += sprintf(&buf[mlen], "SF_ARCHIVED | ");
2233 if (ti->arg2 & SF_IMMUTABLE)
2234 mlen += sprintf(&buf[mlen], "SF_IMMUTABLE | ");
2235 if (ti->arg2 & SF_APPEND)
2236 mlen += sprintf(&buf[mlen], "SF_APPEND | ");
2237
2238 if (ti->arg2 == 0)
2239 mlen += sprintf(&buf[mlen], "CLEAR_ALL_FLAGS | ");
2240 else if (ti->arg2 & ~(UF_NODUMP | UF_IMMUTABLE | UF_APPEND | SF_ARCHIVED | SF_IMMUTABLE | SF_APPEND))
2241 mlen += sprintf(&buf[mlen], "UNKNOWN | ");
2242
2243 if (mlen >= 3)
2244 mlen -= 3;
2245
2246 buf[mlen++] = '>';
2247 buf[mlen] = '\0';
2248
2249 if (mlen < 19) {
2250 memset(&buf[mlen], ' ', 19 - mlen);
2251 mlen = 19;
2252 buf[mlen] = '\0';
2253 }
2254
2255 clen += printf("%s", buf);
2256
2257 nopadding = 1;
2258 break;
2259 }
2260
2261 case FMT_UMASK:
2262 case FMT_FCHMOD:
2263 case FMT_FCHMOD_EXT:
2264 case FMT_CHMOD:
2265 case FMT_CHMOD_EXT:
2266 case FMT_CHMODAT:
2267 {
2268 /*
2269 * fchmod, fchmod_extended, chmod, chmod_extended
2270 */
2271 unsigned long mode;
2272
2273 if (format == FMT_FCHMOD || format == FMT_FCHMOD_EXT) {
2274 if (event->arg1)
2275 clen += printf(" F=%-3d[%3d] ", (int)ti->arg1, (int)event->arg1);
2276 else
2277 clen += printf(" F=%-3d ", (int)ti->arg1);
2278 } else {
2279 if (event->arg1)
2280 clen += printf(" [%3d] ", (int)event->arg1);
2281 else
2282 clen += printf(" ");
2283 }
2284
2285 if (format == FMT_UMASK)
2286 mode = ti->arg1;
2287 else if (format == FMT_FCHMOD || format == FMT_CHMOD || format == FMT_CHMODAT)
2288 mode = ti->arg2;
2289 else
2290 mode = ti->arg4;
2291
2292 get_mode_string(mode, &buf[0]);
2293
2294 if (event->arg1 == 0)
2295 clen += printf("<%s> ", buf);
2296 else
2297 clen += printf("<%s>", buf);
2298 break;
2299 }
2300
2301 case FMT_ACCESS:
2302 {
2303 /*
2304 * access
2305 */
2306 char mode[5];
2307
2308 memset(mode, '_', 4);
2309 mode[4] = '\0';
2310
2311 if (ti->arg2 & R_OK)
2312 mode[0] = 'R';
2313 if (ti->arg2 & W_OK)
2314 mode[1] = 'W';
2315 if (ti->arg2 & X_OK)
2316 mode[2] = 'X';
2317 if (ti->arg2 == F_OK)
2318 mode[3] = 'F';
2319
2320 if (event->arg1)
2321 clen += printf(" [%3d] (%s) ", (int)event->arg1, mode);
2322 else
2323 clen += printf(" (%s) ", mode);
2324
2325 nopadding = 1;
2326 break;
2327 }
2328
2329 case FMT_MOUNT:
2330 {
2331 if (event->arg1)
2332 clen += printf(" [%3d] <FLGS=0x%lx> ", (int)event->arg1, ti->arg3);
2333 else
2334 clen += printf(" <FLGS=0x%lx> ", ti->arg3);
2335
2336 nopadding = 1;
2337 break;
2338 }
2339
2340 case FMT_UNMOUNT:
2341 {
2342 char *mountflag;
2343
2344 if (ti->arg2 & MNT_FORCE)
2345 mountflag = "<FORCE>";
2346 else
2347 mountflag = "";
2348
2349 if (event->arg1)
2350 clen += printf(" [%3d] %s ", (int)event->arg1, mountflag);
2351 else
2352 clen += printf(" %s ", mountflag);
2353
2354 nopadding = 1;
2355 break;
2356 }
2357
2358 case FMT_OPENAT:
2359 case FMT_OPEN:
2360 {
2361 /*
2362 * open
2363 */
2364 char mode[7];
2365
2366 memset(mode, '_', 6);
2367 mode[6] = '\0';
2368
2369 if (ti->arg2 & O_RDWR) {
2370 mode[0] = 'R';
2371 mode[1] = 'W';
2372 } else if (ti->arg2 & O_WRONLY) {
2373 mode[1] = 'W';
2374 } else {
2375 mode[0] = 'R';
2376 }
2377
2378 if (ti->arg2 & O_CREAT)
2379 mode[2] = 'C';
2380
2381 if (ti->arg2 & O_APPEND)
2382 mode[3] = 'A';
2383
2384 if (ti->arg2 & O_TRUNC)
2385 mode[4] = 'T';
2386
2387 if (ti->arg2 & O_EXCL)
2388 mode[5] = 'E';
2389
2390 if (event->arg1)
2391 clen += printf(" [%3d] (%s) ", (int)event->arg1, mode);
2392 else
2393 clen += printf(" F=%-3d (%s) ", (int)event->arg2, mode);
2394
2395 nopadding = 1;
2396 break;
2397 }
2398
2399 case FMT_SOCKET:
2400 {
2401 /*
2402 * socket
2403 *
2404 */
2405 char *domain;
2406 char *type;
2407
2408 switch (ti->arg1) {
2409 case AF_UNIX:
2410 domain = "AF_UNIX";
2411 break;
2412
2413 case AF_INET:
2414 domain = "AF_INET";
2415 break;
2416
2417 case AF_ISO:
2418 domain = "AF_ISO";
2419 break;
2420
2421 case AF_NS:
2422 domain = "AF_NS";
2423 break;
2424
2425 case AF_IMPLINK:
2426 domain = "AF_IMPLINK";
2427 break;
2428
2429 default:
2430 domain = "UNKNOWN";
2431 break;
2432 }
2433
2434 switch (ti->arg2) {
2435 case SOCK_STREAM:
2436 type = "SOCK_STREAM";
2437 break;
2438 case SOCK_DGRAM:
2439 type = "SOCK_DGRAM";
2440 break;
2441 case SOCK_RAW:
2442 type = "SOCK_RAW";
2443 break;
2444 default:
2445 type = "UNKNOWN";
2446 break;
2447 }
2448
2449 if (event->arg1)
2450 clen += printf(" [%3d] <%s, %s, 0x%lx>", (int)event->arg1, domain, type, ti->arg3);
2451 else
2452 clen += printf(" F=%-3d <%s, %s, 0x%lx>", (int)event->arg2, domain, type, ti->arg3);
2453
2454 break;
2455 }
2456
2457 case FMT_AIO_FSYNC:
2458 {
2459 /*
2460 * aio_fsync [errno] AIOCBP OP
2461 */
2462 char *op;
2463
2464 if (ti->arg1 == O_SYNC || ti->arg1 == 0)
2465 op = "AIO_FSYNC";
2466 #if O_DSYNC
2467 else if (ti->arg1 == O_DSYNC)
2468 op = "AIO_DSYNC";
2469 #endif
2470 else
2471 op = "UNKNOWN";
2472
2473 if (event->arg1)
2474 clen += printf(" [%3d] P=0x%8.8lx <%s>", (int)event->arg1, ti->arg2, op);
2475 else
2476 clen += printf(" P=0x%8.8lx <%s>", ti->arg2, op);
2477
2478 break;
2479 }
2480
2481 case FMT_AIO_RETURN:
2482 /*
2483 * aio_return [errno] AIOCBP IOSIZE
2484 */
2485 if (event->arg1)
2486 clen += printf(" [%3d] P=0x%8.8lx", (int)event->arg1, ti->arg1);
2487 else
2488 clen += printf(" P=0x%8.8lx B=0x%-8lx", ti->arg1, event->arg2);
2489
2490 break;
2491
2492 case FMT_AIO_SUSPEND:
2493 /*
2494 * aio_suspend [errno] NENTS
2495 */
2496 if (event->arg1)
2497 clen += printf(" [%3d] N=%d", (int)event->arg1, (int)ti->arg2);
2498 else
2499 clen += printf(" N=%d", (int)ti->arg2);
2500
2501 break;
2502
2503 case FMT_AIO_CANCEL:
2504 /*
2505 * aio_cancel [errno] FD or AIOCBP (if non-null)
2506 */
2507 if (ti->arg2) {
2508 if (event->arg1)
2509 clen += printf(" [%3d] P=0x%8.8lx", (int)event->arg1, ti->arg2);
2510 else
2511 clen += printf(" P=0x%8.8lx", ti->arg2);
2512 } else {
2513 if (event->arg1)
2514 clen += printf(" F=%-3d[%3d]", (int)ti->arg1, (int)event->arg1);
2515 else
2516 clen += printf(" F=%-3d", (int)ti->arg1);
2517 }
2518
2519 break;
2520
2521 case FMT_AIO:
2522 /*
2523 * aio_error, aio_read, aio_write [errno] AIOCBP
2524 */
2525 if (event->arg1)
2526 clen += printf(" [%3d] P=0x%8.8lx", (int)event->arg1, ti->arg1);
2527 else
2528 clen += printf(" P=0x%8.8lx", ti->arg1);
2529
2530 break;
2531
2532 case FMT_LIO_LISTIO: {
2533 /*
2534 * lio_listio [errno] NENTS MODE
2535 */
2536 char *op;
2537
2538 if (ti->arg1 == LIO_NOWAIT)
2539 op = "LIO_NOWAIT";
2540 else if (ti->arg1 == LIO_WAIT)
2541 op = "LIO_WAIT";
2542 else
2543 op = "UNKNOWN";
2544
2545 if (event->arg1)
2546 clen += printf(" [%3d] N=%d <%s>", (int)event->arg1, (int)ti->arg3, op);
2547 else
2548 clen += printf(" N=%d <%s>", (int)ti->arg3, op);
2549
2550 break;
2551 }
2552 }
2553 }
2554
2555 /*
2556 * Calculate space available to print pathname
2557 */
2558 if (columns > MAXCOLS || wideflag)
2559 clen = columns - (clen + 14 + 20 + 11);
2560 else
2561 clen = columns - (clen + 14 + 12);
2562
2563 if (!nopadding)
2564 clen -= 3;
2565
2566 if (framework_name) {
2567 len = sprintf(&buf[0], " %s %s ", framework_type, framework_name);
2568 } else if (*pathname != '\0') {
2569 switch(format) {
2570 case FMT_AT:
2571 case FMT_OPENAT:
2572 case FMT_CHMODAT:
2573 len = sprintf(&buf[0], " [%d]/%s ", (int)ti->arg1, pathname);
2574 break;
2575 case FMT_RENAMEAT:
2576 len = sprintf(&buf[0], " [%d]/%s ", (int)ti->arg3, pathname);
2577 break;
2578 default:
2579 len = sprintf(&buf[0], " %s ", pathname);
2580 }
2581
2582 if (format == FMT_MOUNT && ti->pathname2[0] != '\0') {
2583 int len2;
2584
2585 memset(&buf[len], ' ', 2);
2586
2587 len2 = sprintf(&buf[len+2], " %s ", ti->pathname2);
2588 len = len + 2 + len2;
2589 }
2590 } else {
2591 len = 0;
2592 }
2593
2594 if (clen > len) {
2595 /*
2596 * Add null padding if column length
2597 * is wider than the pathname length.
2598 */
2599 memset(&buf[len], ' ', clen - len);
2600 buf[clen] = '\0';
2601
2602 pathname = buf;
2603 } else if (clen == len) {
2604 pathname = buf;
2605 } else if ((clen > 0) && (clen < len)) {
2606 /*
2607 * This prints the tail end of the pathname
2608 */
2609 buf[len-clen] = ' ';
2610
2611 pathname = &buf[len - clen];
2612 } else {
2613 pathname = "";
2614 }
2615
2616 /*
2617 * fudge some additional system call overhead
2618 * that currently isn't tracked... this also
2619 * insures that we see a minimum of 1 us for
2620 * an elapsed time
2621 */
2622 usecs = (mach_to_nano(now - stime) + (NSEC_PER_USEC - 1)) / NSEC_PER_USEC;
2623 secs = usecs / USEC_PER_SEC;
2624 usecs -= secs * USEC_PER_SEC;
2625
2626 if (!nopadding)
2627 p1 = " ";
2628 else
2629 p1 = "";
2630
2631 if (waited)
2632 p2 = " W";
2633 else
2634 p2 = " ";
2635
2636 if (columns > MAXCOLS || wideflag)
2637 printf("%s%s %3llu.%06llu%s %s.%lu\n", p1, pathname, secs, usecs, p2, command_name, threadid);
2638 else
2639 printf("%s%s %3llu.%06llu%s %-12.12s\n", p1, pathname, secs, usecs, p2, command_name);
2640
2641 if (!RAW_flag)
2642 fflush(stdout);
2643 }
2644
2645 #pragma mark metadata info hash routines
2646
2647 #define VN_HASH_SIZE 16384
2648 #define VN_HASH_MASK (VN_HASH_SIZE - 1)
2649
2650 typedef struct meta_info {
2651 struct meta_info *m_next;
2652 uint64_t m_blkno;
2653 char m_name[MAXPATHLEN];
2654 } *meta_info_t;
2655
2656 meta_info_t m_info_hash[VN_HASH_SIZE];
2657
2658 void
2659 meta_add_name(uint64_t blockno, const char *pathname)
2660 {
2661 meta_info_t mi;
2662 int hashid;
2663
2664 hashid = blockno & VN_HASH_MASK;
2665
2666 for (mi = m_info_hash[hashid]; mi; mi = mi->m_next) {
2667 if (mi->m_blkno == blockno)
2668 break;
2669 }
2670
2671 if (mi == NULL) {
2672 mi = malloc(sizeof (struct meta_info));
2673
2674 mi->m_next = m_info_hash[hashid];
2675 m_info_hash[hashid] = mi;
2676 mi->m_blkno = blockno;
2677 }
2678
2679 strncpy(mi->m_name, pathname, sizeof (mi->m_name));
2680 }
2681
2682 const char *
2683 meta_find_name(uint64_t blockno)
2684 {
2685 meta_info_t mi;
2686 int hashid;
2687
2688 hashid = blockno & VN_HASH_MASK;
2689
2690 for (mi = m_info_hash[hashid]; mi; mi = mi->m_next) {
2691 if (mi->m_blkno == blockno)
2692 return mi->m_name;
2693 }
2694
2695 return "";
2696 }
2697
2698 void
2699 meta_delete_all(void)
2700 {
2701 meta_info_t mi, next;
2702 int i;
2703
2704 for (i = 0; i < HASH_MASK; i++) {
2705 for (mi = m_info_hash[i]; mi; mi = next) {
2706 next = mi->m_next;
2707
2708 free(mi);
2709 }
2710
2711 m_info_hash[i] = NULL;
2712 }
2713 }
2714
2715 #pragma mark event ("thread info") routines
2716
2717 th_info_t th_info_hash[HASH_SIZE];
2718 th_info_t th_info_freelist;
2719
2720 static th_info_t
2721 add_event(ktrace_event_t event, int type)
2722 {
2723 th_info_t ti;
2724 int hashid;
2725 unsigned long eventid;
2726
2727 if ((ti = th_info_freelist))
2728 th_info_freelist = ti->next;
2729 else
2730 ti = malloc(sizeof (struct th_info));
2731
2732 bzero(ti, sizeof (struct th_info));
2733
2734 hashid = event->threadid & HASH_MASK;
2735
2736 ti->next = th_info_hash[hashid];
2737 th_info_hash[hashid] = ti;
2738
2739 eventid = event->debugid & KDBG_EVENTID_MASK;
2740
2741 if (eventid == BSC_execve || eventid == BSC_posix_spawn) {
2742 const char *command;
2743
2744 command = ktrace_get_execname_for_thread(s, event->threadid);
2745
2746 if (!command)
2747 command = "";
2748
2749 strncpy(ti->command, command, sizeof (ti->command));
2750 ti->command[MAXCOMLEN] = '\0';
2751 }
2752
2753 ti->thread = event->threadid;
2754 ti->type = type;
2755
2756 return ti;
2757 }
2758
2759 th_info_t
2760 event_find(uintptr_t thread, int type)
2761 {
2762 th_info_t ti;
2763 int hashid;
2764
2765 hashid = thread & HASH_MASK;
2766
2767 for (ti = th_info_hash[hashid]; ti; ti = ti->next) {
2768 if (ti->thread == thread) {
2769 if (type == ti->type)
2770 return ti;
2771
2772 if (type == 0)
2773 return ti;
2774 }
2775 }
2776
2777 return NULL;
2778 }
2779
2780 void
2781 event_delete(th_info_t ti_to_delete)
2782 {
2783 th_info_t ti;
2784 th_info_t ti_prev;
2785 int hashid;
2786
2787 hashid = ti_to_delete->thread & HASH_MASK;
2788
2789 if ((ti = th_info_hash[hashid])) {
2790 if (ti == ti_to_delete)
2791 th_info_hash[hashid] = ti->next;
2792 else {
2793 ti_prev = ti;
2794
2795 for (ti = ti->next; ti; ti = ti->next) {
2796 if (ti == ti_to_delete) {
2797 ti_prev->next = ti->next;
2798 break;
2799 }
2800 ti_prev = ti;
2801 }
2802 }
2803 if (ti) {
2804 ti->next = th_info_freelist;
2805 th_info_freelist = ti;
2806 }
2807 }
2808 }
2809
2810 void
2811 event_delete_all(void)
2812 {
2813 th_info_t ti = 0;
2814 th_info_t ti_next = 0;
2815 int i;
2816
2817 for (i = 0; i < HASH_SIZE; i++) {
2818
2819 for (ti = th_info_hash[i]; ti; ti = ti_next) {
2820 ti_next = ti->next;
2821 ti->next = th_info_freelist;
2822 th_info_freelist = ti;
2823 }
2824 th_info_hash[i] = 0;
2825 }
2826 }
2827
2828 void
2829 event_enter(int type, ktrace_event_t event)
2830 {
2831 th_info_t ti;
2832
2833 #if DEBUG
2834 int index;
2835 bool found;
2836
2837 found = false;
2838
2839 switch (type) {
2840 case P_CS_SYNC_DISK:
2841 case MACH_pageout:
2842 case MACH_vmfault:
2843 case MSC_map_fd:
2844 case SPEC_ioctl:
2845 case Throttled:
2846 case HFS_update:
2847 found = true;
2848 }
2849
2850 if ((type & CSC_MASK) == BSC_BASE) {
2851 if ((index = BSC_INDEX(type)) < MAX_BSD_SYSCALL && bsd_syscalls[index].sc_name)
2852 found = true;
2853 }
2854
2855 assert(found);
2856 #endif /* DEBUG */
2857
2858 if ((ti = add_event(event, type)) == NULL)
2859 return;
2860
2861 ti->stime = event->timestamp;
2862 ti->arg1 = event->arg1;
2863 ti->arg2 = event->arg2;
2864 ti->arg3 = event->arg3;
2865 ti->arg4 = event->arg4;
2866 }
2867
2868 void
2869 event_exit(char *sc_name, int type, ktrace_event_t event, int format)
2870 {
2871 th_info_t ti;
2872 pid_t pid;
2873
2874 if ((ti = event_find(event->threadid, type)) == NULL)
2875 return;
2876
2877 pid = ktrace_get_pid_for_thread(s, event->threadid);
2878
2879 if (check_filter_mode(pid, ti, type, (int)event->arg1, (int)event->arg2, sc_name)) {
2880 const char *pathname;
2881
2882 pathname = NULL;
2883
2884 /* most things are just interested in the first lookup */
2885 if (ti->pathname[0] != '\0')
2886 pathname = ti->pathname;
2887
2888 if (!pathname)
2889 pathname = "";
2890
2891 format_print(ti, sc_name, event, type, format, event->timestamp, ti->stime, ti->waited, pathname, NULL);
2892 }
2893
2894 event_delete(ti);
2895 }
2896
2897 void
2898 event_mark_thread_waited(uintptr_t thread)
2899 {
2900 th_info_t ti;
2901 int hashid;
2902
2903 hashid = thread & HASH_MASK;
2904
2905 for (ti = th_info_hash[hashid]; ti; ti = ti->next) {
2906 if (ti->thread == thread)
2907 ti->waited = 1;
2908 }
2909 }
2910
2911 #pragma mark network fd set routines
2912
2913 struct pid_fd_set {
2914 struct pid_fd_set *next;
2915 pid_t pid;
2916 char *set;
2917 size_t setsize; /* number of *bytes*, not bits */
2918 };
2919
2920 struct pid_fd_set *pfs_hash[HASH_SIZE];
2921
2922 static struct pid_fd_set *
2923 pfs_get(pid_t pid)
2924 {
2925 struct pid_fd_set *pfs;
2926 int hashid;
2927
2928 assert(pid >= 0);
2929
2930 hashid = pid & HASH_MASK;
2931
2932 for (pfs = pfs_hash[hashid]; pfs; pfs = pfs->next) {
2933 if (pfs->pid == pid) {
2934 return pfs;
2935 }
2936 }
2937
2938 pfs = calloc(1, sizeof (struct pid_fd_set));
2939
2940 pfs->pid = pid;
2941 pfs->set = NULL;
2942 pfs->setsize = 0;
2943 pfs->next = pfs_hash[hashid];
2944 pfs_hash[hashid] = pfs;
2945
2946 return pfs;
2947 }
2948
2949 void
2950 fd_clear_pid(pid_t pid)
2951 {
2952 struct pid_fd_set *pfs, *prev;
2953 int hashid;
2954
2955 if (pid < 0)
2956 return;
2957
2958 hashid = pid & HASH_MASK;
2959
2960 pfs = pfs_hash[hashid];
2961 prev = NULL;
2962
2963 while (pfs) {
2964 if (pfs->pid == pid) {
2965 if (prev) {
2966 prev->next = pfs->next;
2967 } else {
2968 pfs_hash[hashid] = pfs->next;
2969 }
2970
2971 free(pfs->set);
2972 free(pfs);
2973
2974 break;
2975 } else {
2976 prev = pfs;
2977 pfs = pfs->next;
2978 }
2979 }
2980 }
2981
2982 void
2983 fd_clear_all(void)
2984 {
2985 struct pid_fd_set *pfs, *next;
2986 int i;
2987
2988 for (i = 0; i < HASH_SIZE; i++) {
2989 for (pfs = pfs_hash[i]; pfs; pfs = next) {
2990 next = pfs->next;
2991
2992 free(pfs->set);
2993 free(pfs);
2994 }
2995
2996 pfs_hash[i] = NULL;
2997 }
2998 }
2999
3000 void
3001 fd_set_is_network(pid_t pid, unsigned long fd, bool set)
3002 {
3003 struct pid_fd_set *pfs;
3004
3005 if (pid < 0)
3006 return;
3007 if (fd > OPEN_MAX)
3008 return;
3009
3010 pfs = pfs_get(pid);
3011
3012 if (fd >= pfs->setsize * CHAR_BIT) {
3013 size_t newsize;
3014
3015 if (!set) return;
3016
3017 newsize = MAX((fd + CHAR_BIT) / CHAR_BIT, 2 * pfs->setsize);
3018 pfs->set = reallocf(pfs->set, newsize);
3019 assert(pfs->set != NULL);
3020
3021 bzero(pfs->set + pfs->setsize, newsize - pfs->setsize);
3022 pfs->setsize = newsize;
3023 }
3024
3025 if (set)
3026 setbit(pfs->set, fd);
3027 else
3028 clrbit(pfs->set, fd);
3029 }
3030
3031 bool
3032 fd_is_network(pid_t pid, unsigned long fd)
3033 {
3034 struct pid_fd_set *pfs;
3035
3036 if (pid < 0)
3037 return false;
3038
3039 pfs = pfs_get(pid);
3040
3041 if (fd >= pfs->setsize * CHAR_BIT) {
3042 return false;
3043 }
3044
3045 return isset(pfs->set, fd);
3046 }
3047
3048 #pragma mark shared region address lookup routines
3049
3050 #define MAXINDEX 2048
3051
3052 struct library_range {
3053 uint64_t b_address;
3054 uint64_t e_address;
3055 };
3056
3057 struct library_info {
3058 uint64_t b_address;
3059 uint64_t e_address;
3060 int r_type;
3061 char *name;
3062 };
3063
3064 struct library_range framework32 = {0, 0};
3065 struct library_range framework64 = {0, 0};
3066 struct library_range framework64h = {0, 0};
3067
3068 struct library_info library_infos[MAXINDEX];
3069 int num_libraries = 0;
3070
3071 #define TEXT_R 0
3072 #define DATA_R 1
3073 #define OBJC_R 2
3074 #define IMPORT_R 3
3075 #define UNICODE_R 4
3076 #define IMAGE_R 5
3077 #define LINKEDIT_R 6
3078
3079 static void
3080 sort_library_addresses(void)
3081 {
3082 library_infos[num_libraries].b_address = library_infos[num_libraries - 1].b_address + 0x800000;
3083 library_infos[num_libraries].e_address = library_infos[num_libraries].b_address;
3084 library_infos[num_libraries].name = NULL;
3085
3086 qsort_b(library_infos, num_libraries, sizeof (struct library_info), ^int(const void *aa, const void *bb) {
3087 struct library_info *a = (struct library_info *)aa;
3088 struct library_info *b = (struct library_info *)bb;
3089
3090 if (a->b_address < b->b_address) return -1;
3091 if (a->b_address == b->b_address) return 0;
3092 return 1;
3093 });
3094 }
3095
3096 static int
3097 scanline(char *inputstring, char **argv, int maxtokens)
3098 {
3099 int n = 0;
3100 char **ap = argv, *p, *val;
3101
3102 for (p = inputstring; n < maxtokens && p != NULL; ) {
3103 while ((val = strsep(&p, " \t")) != NULL && *val == '\0') ;
3104
3105 *ap++ = val;
3106 n++;
3107 }
3108
3109 *ap = 0;
3110
3111 return n;
3112 }
3113
3114 static int
3115 read_shared_cache_map(const char *path, struct library_range *lr, char *linkedit_name)
3116 {
3117 uint64_t b_address, e_address;
3118 char buf[1024];
3119 char *fnp, *fn_tofree;
3120 FILE *fd;
3121 char frameworkName[256];
3122 char *tokens[64];
3123 int ntokens;
3124 int type;
3125 int linkedit_found = 0;
3126 char *substring, *ptr;
3127
3128 bzero(buf, sizeof(buf));
3129 bzero(tokens, sizeof(tokens));
3130
3131 lr->b_address = 0;
3132 lr->e_address = 0;
3133
3134 if ((fd = fopen(path, "r")) == 0)
3135 return 0;
3136
3137 while (fgets(buf, 1023, fd)) {
3138 if (strncmp(buf, "mapping", 7))
3139 break;
3140 }
3141
3142 buf[strlen(buf)-1] = 0;
3143
3144 frameworkName[0] = 0;
3145
3146 for (;;) {
3147 /*
3148 * Extract lib name from path name
3149 */
3150 if ((substring = strrchr(buf, '.'))) {
3151 /*
3152 * There is a ".": name is whatever is between the "/" around the "."
3153 */
3154 while ( *substring != '/') /* find "/" before "." */
3155 substring--;
3156
3157 substring++;
3158
3159 strncpy(frameworkName, substring, 256); /* copy path from "/" */
3160 frameworkName[255] = 0;
3161 substring = frameworkName;
3162
3163 while ( *substring != '/' && *substring) /* find "/" after "." and stop string there */
3164 substring++;
3165
3166 *substring = 0;
3167 } else {
3168 /*
3169 * No ".": take segment after last "/"
3170 */
3171 ptr = buf;
3172 substring = ptr;
3173
3174 while (*ptr) {
3175 if (*ptr == '/')
3176 substring = ptr + 1;
3177 ptr++;
3178 }
3179
3180 strncpy(frameworkName, substring, 256);
3181 frameworkName[255] = 0;
3182 }
3183
3184 fnp = malloc(strlen(frameworkName) + 1);
3185 fn_tofree = fnp;
3186 strcpy(fnp, frameworkName);
3187
3188 while (fgets(buf, 1023, fd) && num_libraries < (MAXINDEX - 2)) {
3189 /*
3190 * Get rid of EOL
3191 */
3192 buf[strlen(buf)-1] = 0;
3193
3194 ntokens = scanline(buf, tokens, 64);
3195
3196 if (ntokens < 4)
3197 continue;
3198
3199 if (strncmp(tokens[0], "__TEXT", 6) == 0)
3200 type = TEXT_R;
3201 else if (strncmp(tokens[0], "__DATA", 6) == 0)
3202 type = DATA_R;
3203 else if (strncmp(tokens[0], "__OBJC", 6) == 0)
3204 type = OBJC_R;
3205 else if (strncmp(tokens[0], "__IMPORT", 8) == 0)
3206 type = IMPORT_R;
3207 else if (strncmp(tokens[0], "__UNICODE", 9) == 0)
3208 type = UNICODE_R;
3209 else if (strncmp(tokens[0], "__IMAGE", 7) == 0)
3210 type = IMAGE_R;
3211 else if (strncmp(tokens[0], "__LINKEDIT", 10) == 0)
3212 type = LINKEDIT_R;
3213 else
3214 type = -1;
3215
3216 if (type == LINKEDIT_R && linkedit_found)
3217 break;
3218
3219 if (type != -1) {
3220 b_address = strtoull(tokens[1], 0, 16);
3221 e_address = strtoull(tokens[3], 0, 16);
3222
3223 library_infos[num_libraries].b_address = b_address;
3224 library_infos[num_libraries].e_address = e_address;
3225 library_infos[num_libraries].r_type = type;
3226
3227 if (type == LINKEDIT_R) {
3228 library_infos[num_libraries].name = linkedit_name;
3229 linkedit_found = 1;
3230 } else {
3231 library_infos[num_libraries].name = fnp;
3232 fn_tofree = NULL;
3233 }
3234 #if 0
3235 printf("%s(%d): %qx-%qx\n", frameworkInfo[numFrameworks].name, type, b_address, e_address);
3236 #endif
3237 if (lr->b_address == 0 || b_address < lr->b_address)
3238 lr->b_address = b_address;
3239
3240 if (lr->e_address == 0 || e_address > lr->e_address)
3241 lr->e_address = e_address;
3242
3243 num_libraries++;
3244 }
3245
3246 if (type == LINKEDIT_R)
3247 break;
3248 }
3249
3250 free(fn_tofree);
3251
3252 if (fgets(buf, 1023, fd) == 0)
3253 break;
3254
3255 buf[strlen(buf)-1] = 0;
3256 }
3257
3258 fclose(fd);
3259
3260 #if 0
3261 printf("%s range, %qx-%qx\n", path, lr->b_address, lr->e_address);
3262 #endif
3263 return 1;
3264 }
3265
3266 void
3267 init_shared_cache_mapping(void)
3268 {
3269 read_shared_cache_map("/var/db/dyld/dyld_shared_cache_i386.map", &framework32, "/var/db/dyld/dyld_shared_cache_i386");
3270
3271 if (0 == read_shared_cache_map("/var/db/dyld/dyld_shared_cache_x86_64h.map", &framework64h, "/var/db/dyld/dyld_shared_cache_x86_64h")) {
3272 read_shared_cache_map("/var/db/dyld/dyld_shared_cache_x86_64.map", &framework64, "/var/db/dyld/dyld_shared_cache_x86_64");
3273 }
3274
3275 sort_library_addresses();
3276 }
3277
3278 void
3279 lookup_name(uint64_t user_addr, char **type, char **name)
3280 {
3281 int i;
3282 int start, last;
3283
3284 static char *frameworkType[] = {
3285 "<TEXT> ",
3286 "<DATA> ",
3287 "<OBJC> ",
3288 "<IMPORT> ",
3289 "<UNICODE> ",
3290 "<IMAGE> ",
3291 "<LINKEDIT>",
3292 };
3293
3294 *name = NULL;
3295 *type = NULL;
3296
3297 if (num_libraries) {
3298 if ((user_addr >= framework32.b_address && user_addr < framework32.e_address) ||
3299 (user_addr >= framework64.b_address && user_addr < framework64.e_address) ||
3300 (user_addr >= framework64h.b_address && user_addr < framework64h.e_address)) {
3301
3302 start = 0;
3303 last = num_libraries;
3304
3305 for (i = num_libraries / 2; start < last; i = start + ((last - start) / 2)) {
3306 if (user_addr > library_infos[i].e_address)
3307 start = i+1;
3308 else
3309 last = i;
3310 }
3311
3312 if (start < num_libraries &&
3313 user_addr >= library_infos[start].b_address && user_addr < library_infos[start].e_address) {
3314 *type = frameworkType[library_infos[start].r_type];
3315 *name = library_infos[start].name;
3316 }
3317 }
3318 }
3319 }
3320
3321 #pragma mark disk I/O tracking routines
3322
3323 struct diskio *free_diskios = NULL;
3324 struct diskio *busy_diskios = NULL;
3325
3326 struct diskio *
3327 diskio_start(unsigned long type, unsigned long bp, unsigned long dev,
3328 unsigned long blkno, unsigned long iosize, ktrace_event_t event)
3329 {
3330 const char *command;
3331 struct diskio *dio;
3332
3333 if ((dio = free_diskios)) {
3334 free_diskios = dio->next;
3335 } else {
3336 dio = malloc(sizeof (struct diskio));
3337 }
3338
3339 dio->prev = NULL;
3340
3341 dio->type = type;
3342 dio->bp = bp;
3343 dio->dev = dev;
3344 dio->blkno = blkno;
3345 dio->iosize = iosize;
3346 dio->issued_time = event->timestamp;
3347 dio->issuing_thread = event->threadid;
3348 dio->issuing_pid = ktrace_get_pid_for_thread(s, event->threadid);
3349
3350 dio->bc_info = 0x0;
3351
3352 command = ktrace_get_execname_for_thread(s, event->threadid);
3353
3354 if (!command)
3355 command = "";
3356
3357 strncpy(dio->issuing_command, command, MAXCOMLEN);
3358 dio->issuing_command[MAXCOMLEN] = '\0';
3359
3360 dio->next = busy_diskios;
3361
3362 if (dio->next)
3363 dio->next->prev = dio;
3364
3365 busy_diskios = dio;
3366
3367 return dio;
3368 }
3369
3370 struct diskio *
3371 diskio_find(unsigned long bp)
3372 {
3373 struct diskio *dio;
3374
3375 for (dio = busy_diskios; dio; dio = dio->next) {
3376 if (dio->bp == bp)
3377 return dio;
3378 }
3379
3380 return NULL;
3381 }
3382
3383 struct diskio *
3384 diskio_complete(unsigned long bp, unsigned long io_errno, unsigned long resid,
3385 uintptr_t thread, uint64_t curtime, struct timeval curtime_wall)
3386 {
3387 struct diskio *dio;
3388
3389 if ((dio = diskio_find(bp)) == NULL) return NULL;
3390
3391 if (dio == busy_diskios) {
3392 if ((busy_diskios = dio->next))
3393 dio->next->prev = NULL;
3394 } else {
3395 if (dio->next)
3396 dio->next->prev = dio->prev;
3397 dio->prev->next = dio->next;
3398 }
3399
3400 dio->iosize -= resid;
3401 dio->io_errno = io_errno;
3402 dio->completed_time = curtime;
3403 dio->completed_walltime = curtime_wall;
3404 dio->completion_thread = thread;
3405
3406 return dio;
3407 }
3408
3409 void
3410 diskio_free(struct diskio *dio)
3411 {
3412 dio->next = free_diskios;
3413 free_diskios = dio;
3414 }
3415
3416 void
3417 diskio_print(struct diskio *dio)
3418 {
3419 char *p = NULL;
3420 int len = 0;
3421 unsigned long type;
3422 int format = FMT_DISKIO;
3423 char buf[64];
3424
3425 type = dio->type;
3426 dio->is_meta = 0;
3427
3428 if ((type & P_CS_Class) == P_CS_Class) {
3429 switch (type) {
3430 case P_CS_ReadChunk:
3431 p = " RdChunkCS";
3432 len = 13;
3433 format = FMT_DISKIO_CS;
3434 break;
3435 case P_CS_WriteChunk:
3436 p = " WrChunkCS";
3437 len = 13;
3438 format = FMT_DISKIO_CS;
3439 break;
3440 case P_CS_MetaRead:
3441 p = " RdMetaCS";
3442 len = 10;
3443 format = FMT_DISKIO_CS;
3444 break;
3445 case P_CS_MetaWrite:
3446 p = " WrMetaCS";
3447 len = 10;
3448 format = FMT_DISKIO_CS;
3449 break;
3450 case P_CS_TransformRead:
3451 p = " RdBgTfCS";
3452 len = 10;
3453 break;
3454 case P_CS_TransformWrite:
3455 p = " WrBgTfCS";
3456 len = 10;
3457 break;
3458 case P_CS_MigrationRead:
3459 p = " RdBgMigrCS";
3460 len = 12;
3461 break;
3462 case P_CS_MigrationWrite:
3463 p = " WrBgMigrCS";
3464 len = 12;
3465 break;
3466 default:
3467 p = " CS";
3468 len = 4;
3469 break;
3470 }
3471
3472 strncpy(buf, p, len);
3473 } else {
3474 switch (type & P_DISKIO_TYPE) {
3475 case P_RdMeta:
3476 dio->is_meta = 1;
3477 p = " RdMeta";
3478 len = 8;
3479 break;
3480 case P_WrMeta:
3481 dio->is_meta = 1;
3482 p = " WrMeta";
3483 len = 8;
3484 break;
3485 case P_RdData:
3486 p = " RdData";
3487 len = 8;
3488 break;
3489 case P_WrData:
3490 p = " WrData";
3491 len = 8;
3492 break;
3493 case P_PgIn:
3494 p = " PgIn";
3495 len = 6;
3496 break;
3497 case P_PgOut:
3498 p = " PgOut";
3499 len = 7;
3500 break;
3501 default:
3502 p = " ";
3503 len = 2;
3504 break;
3505 }
3506
3507 strncpy(buf, p, len);
3508
3509 buf[len++] = '[';
3510
3511 if (type & P_DISKIO_ASYNC)
3512 buf[len++] = 'A';
3513 else
3514 buf[len++] = 'S';
3515
3516 if (type & P_DISKIO_NOCACHE)
3517 buf[len++] = 'N';
3518
3519 int tier = (type & P_DISKIO_TIER_MASK) >> P_DISKIO_TIER_SHIFT;
3520
3521 if (tier > 0) {
3522 buf[len++] = 'T';
3523 if (tier > 0 && tier < 10)
3524 buf[len++] = '0' + tier;
3525
3526 if (type & P_DISKIO_TIER_UPGRADE) {
3527 buf[len++] = 'U';
3528 }
3529 }
3530
3531 if (type & P_DISKIO_PASSIVE)
3532 buf[len++] = 'P';
3533
3534 buf[len++] = ']';
3535 }
3536
3537 buf[len] = 0;
3538
3539 if (check_filter_mode(-1, NULL, type, 0, 0, buf))
3540 format_print(NULL, buf, NULL, type, format, dio->completed_time, dio->issued_time, 1, "", dio);
3541 }
3542
3543 #pragma mark disk name routines
3544
3545 struct diskrec {
3546 struct diskrec *next;
3547 char *diskname;
3548 int dev;
3549 };
3550
3551 struct diskrec *disk_list = NULL;
3552
3553 void
3554 cache_disk_names(void)
3555 {
3556 struct stat st;
3557 DIR *dirp = NULL;
3558 struct dirent *dir;
3559 struct diskrec *dnp;
3560
3561 if ((dirp = opendir("/dev")) == NULL)
3562 return;
3563
3564 while ((dir = readdir(dirp)) != NULL) {
3565 char nbuf[MAXPATHLEN];
3566
3567 if (dir->d_namlen < 5 || strncmp("disk", dir->d_name, 4))
3568 continue;
3569
3570 snprintf(nbuf, MAXPATHLEN, "%s/%s", "/dev", dir->d_name);
3571
3572 if (stat(nbuf, &st) < 0)
3573 continue;
3574
3575 if ((dnp = malloc(sizeof(struct diskrec))) == NULL)
3576 continue;
3577
3578 if ((dnp->diskname = malloc(dir->d_namlen + 1)) == NULL) {
3579 free(dnp);
3580 continue;
3581 }
3582 strncpy(dnp->diskname, dir->d_name, dir->d_namlen);
3583 dnp->diskname[dir->d_namlen] = 0;
3584 dnp->dev = st.st_rdev;
3585
3586 dnp->next = disk_list;
3587 disk_list = dnp;
3588 }
3589
3590 closedir(dirp);
3591 }
3592
3593 static void
3594 recache_disk_names(void)
3595 {
3596 struct diskrec *dnp, *next_dnp;
3597
3598 for (dnp = disk_list; dnp; dnp = next_dnp) {
3599 next_dnp = dnp->next;
3600
3601 free(dnp->diskname);
3602 free(dnp);
3603 }
3604
3605 disk_list = NULL;
3606 cache_disk_names();
3607 }
3608
3609 char *
3610 find_disk_name(unsigned long dev)
3611 {
3612 struct diskrec *dnp;
3613 int i;
3614
3615 if (dev == NFS_DEV)
3616 return ("NFS");
3617
3618 if (dev == CS_DEV)
3619 return ("CS");
3620
3621 for (i = 0; i < 2; i++) {
3622 for (dnp = disk_list; dnp; dnp = dnp->next) {
3623 if (dnp->dev == dev)
3624 return (dnp->diskname);
3625 }
3626 recache_disk_names();
3627 }
3628
3629 return "NOTFOUND";
3630 }
3631
3632 char *
3633 generate_cs_disk_name(unsigned long dev, char *s)
3634 {
3635 if (dev == -1)
3636 return "UNKNOWN";
3637
3638 sprintf(s, "disk%lus%lu", (dev >> 16) & 0xffff, dev & 0xffff);
3639
3640 return (s);
3641 }