1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "spdk/stdinc.h" 35 #include "spdk/log.h" 36 #include "spdk/trace_parser.h" 37 38 #include <exception> 39 #include <new> 40 41 struct spdk_trace_parser { 42 spdk_trace_parser(const spdk_trace_parser_opts *opts); 43 ~spdk_trace_parser(); 44 spdk_trace_parser(const spdk_trace_parser &) = delete; 45 spdk_trace_parser &operator=(const spdk_trace_parser &) = delete; 46 private: 47 bool init(const spdk_trace_parser_opts *opts); 48 void cleanup(); 49 50 spdk_trace_histories *_histories; 51 size_t _map_size; 52 int _fd; 53 }; 54 55 bool 56 spdk_trace_parser::init(const spdk_trace_parser_opts *opts) 57 { 58 struct stat st; 59 int rc; 60 61 switch (opts->mode) { 62 case SPDK_TRACE_PARSER_MODE_FILE: 63 _fd = open(opts->filename, O_RDONLY); 64 break; 65 case SPDK_TRACE_PARSER_MODE_SHM: 66 _fd = shm_open(opts->filename, O_RDONLY, 0600); 67 break; 68 default: 69 SPDK_ERRLOG("Invalid mode: %d\n", opts->mode); 70 return false; 71 } 72 73 if (_fd < 0) { 74 SPDK_ERRLOG("Could not open trace file: %s (%d)\n", opts->filename, errno); 75 return false; 76 } 77 78 rc = fstat(_fd, &st); 79 if (rc < 0) { 80 SPDK_ERRLOG("Could not get size of trace file: %s\n", opts->filename); 81 return false; 82 } 83 84 if ((size_t)st.st_size < sizeof(*_histories)) { 85 SPDK_ERRLOG("Invalid trace file: %s\n", opts->filename); 86 return false; 87 } 88 89 /* Map the header of trace file */ 90 _map_size = sizeof(*_histories); 91 _histories = static_cast<spdk_trace_histories *>(mmap(NULL, _map_size, PROT_READ, 92 MAP_SHARED, _fd, 0)); 93 if (_histories == MAP_FAILED) { 94 SPDK_ERRLOG("Could not mmap trace file: %s\n", opts->filename); 95 _histories = NULL; 96 return false; 97 } 98 99 /* Remap the entire trace file */ 100 _map_size = spdk_get_trace_histories_size(_histories); 101 munmap(_histories, sizeof(*_histories)); 102 if ((size_t)st.st_size < _map_size) { 103 SPDK_ERRLOG("Trace file %s is not valid\n", opts->filename); 104 _histories = NULL; 105 return false; 106 } 107 _histories = static_cast<spdk_trace_histories *>(mmap(NULL, _map_size, PROT_READ, 108 MAP_SHARED, _fd, 0)); 109 if (_histories == MAP_FAILED) { 110 SPDK_ERRLOG("Could not mmap trace file: %s\n", opts->filename); 111 _histories = NULL; 112 return false; 113 } 114 115 return true; 116 } 117 118 void 119 spdk_trace_parser::cleanup() 120 { 121 if (_histories != NULL) { 122 munmap(_histories, _map_size); 123 } 124 125 if (_fd > 0) { 126 close(_fd); 127 } 128 } 129 130 spdk_trace_parser::spdk_trace_parser(const spdk_trace_parser_opts *opts) : 131 _histories(NULL), 132 _map_size(0), 133 _fd(-1) 134 { 135 if (!init(opts)) { 136 cleanup(); 137 throw std::exception(); 138 } 139 } 140 141 spdk_trace_parser::~spdk_trace_parser() 142 { 143 cleanup(); 144 } 145 146 struct spdk_trace_parser * 147 spdk_trace_parser_init(const struct spdk_trace_parser_opts *opts) 148 { 149 try { 150 return new spdk_trace_parser(opts); 151 } catch (...) { 152 return NULL; 153 } 154 } 155 156 void 157 spdk_trace_parser_cleanup(struct spdk_trace_parser *parser) 158 { 159 delete parser; 160 } 161