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 #include "spdk/util.h" 38 39 #include <exception> 40 #include <new> 41 42 struct spdk_trace_parser { 43 spdk_trace_parser(const spdk_trace_parser_opts *opts); 44 ~spdk_trace_parser(); 45 spdk_trace_parser(const spdk_trace_parser &) = delete; 46 spdk_trace_parser &operator=(const spdk_trace_parser &) = delete; 47 const spdk_trace_flags *flags() const { return &_histories->flags; } 48 private: 49 bool init(const spdk_trace_parser_opts *opts); 50 void cleanup(); 51 52 spdk_trace_histories *_histories; 53 size_t _map_size; 54 int _fd; 55 }; 56 57 bool 58 spdk_trace_parser::init(const spdk_trace_parser_opts *opts) 59 { 60 struct stat st; 61 int rc; 62 63 switch (opts->mode) { 64 case SPDK_TRACE_PARSER_MODE_FILE: 65 _fd = open(opts->filename, O_RDONLY); 66 break; 67 case SPDK_TRACE_PARSER_MODE_SHM: 68 _fd = shm_open(opts->filename, O_RDONLY, 0600); 69 break; 70 default: 71 SPDK_ERRLOG("Invalid mode: %d\n", opts->mode); 72 return false; 73 } 74 75 if (_fd < 0) { 76 SPDK_ERRLOG("Could not open trace file: %s (%d)\n", opts->filename, errno); 77 return false; 78 } 79 80 rc = fstat(_fd, &st); 81 if (rc < 0) { 82 SPDK_ERRLOG("Could not get size of trace file: %s\n", opts->filename); 83 return false; 84 } 85 86 if ((size_t)st.st_size < sizeof(*_histories)) { 87 SPDK_ERRLOG("Invalid trace file: %s\n", opts->filename); 88 return false; 89 } 90 91 /* Map the header of trace file */ 92 _map_size = sizeof(*_histories); 93 _histories = static_cast<spdk_trace_histories *>(mmap(NULL, _map_size, PROT_READ, 94 MAP_SHARED, _fd, 0)); 95 if (_histories == MAP_FAILED) { 96 SPDK_ERRLOG("Could not mmap trace file: %s\n", opts->filename); 97 _histories = NULL; 98 return false; 99 } 100 101 /* Remap the entire trace file */ 102 _map_size = spdk_get_trace_histories_size(_histories); 103 munmap(_histories, sizeof(*_histories)); 104 if ((size_t)st.st_size < _map_size) { 105 SPDK_ERRLOG("Trace file %s is not valid\n", opts->filename); 106 _histories = NULL; 107 return false; 108 } 109 _histories = static_cast<spdk_trace_histories *>(mmap(NULL, _map_size, PROT_READ, 110 MAP_SHARED, _fd, 0)); 111 if (_histories == MAP_FAILED) { 112 SPDK_ERRLOG("Could not mmap trace file: %s\n", opts->filename); 113 _histories = NULL; 114 return false; 115 } 116 117 return true; 118 } 119 120 void 121 spdk_trace_parser::cleanup() 122 { 123 if (_histories != NULL) { 124 munmap(_histories, _map_size); 125 } 126 127 if (_fd > 0) { 128 close(_fd); 129 } 130 } 131 132 spdk_trace_parser::spdk_trace_parser(const spdk_trace_parser_opts *opts) : 133 _histories(NULL), 134 _map_size(0), 135 _fd(-1) 136 { 137 if (!init(opts)) { 138 cleanup(); 139 throw std::exception(); 140 } 141 } 142 143 spdk_trace_parser::~spdk_trace_parser() 144 { 145 cleanup(); 146 } 147 148 struct spdk_trace_parser * 149 spdk_trace_parser_init(const struct spdk_trace_parser_opts *opts) 150 { 151 try { 152 return new spdk_trace_parser(opts); 153 } catch (...) { 154 return NULL; 155 } 156 } 157 158 void 159 spdk_trace_parser_cleanup(struct spdk_trace_parser *parser) 160 { 161 delete parser; 162 } 163 164 const struct spdk_trace_flags * 165 spdk_trace_parser_get_flags(const struct spdk_trace_parser *parser) 166 { 167 return parser->flags(); 168 } 169