// -*- mode:c++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * ceph - scalable distributed file system * * copyright (c) 2014 john spray * * this is free software; you can redistribute it and/or * modify it under the terms of the gnu lesser general public * license version 2.1, as published by the free software * foundation. see file copying. */ #include "JournalFilter.h" #include "common/ceph_argparse.h" #include "mds/events/ESession.h" #include "mds/events/EUpdate.h" #define dout_context g_ceph_context #define dout_subsys ceph_subsys_mds const string JournalFilter::range_separator(".."); /* * Return whether a LogEvent is to be included or excluded. * * The filter parameters are applied on an AND basis: if any * condition is not met, the event is excluded. Try to do * the fastest checks first. */ bool JournalFilter::apply(uint64_t pos, LogEvent &le) const { /* Filtering by journal offset range */ if (pos < range_start || pos >= range_end) { return false; } /* Filtering by event type */ if (event_type != 0) { if (le.get_type() != event_type) { return false; } } /* Filtering by client */ if (client_name.num()) { EMetaBlob const *metablob = le.get_metablob(); if (metablob) { if (metablob->get_client_name() != client_name) { return false; } } else if (le.get_type() == EVENT_SESSION) { ESession *es = reinterpret_cast(&le); if (es->get_client_inst().name != client_name) { return false; } } else { return false; } } /* Filtering by inode */ if (inode) { EMetaBlob const *metablob = le.get_metablob(); if (metablob) { std::set inodes; metablob->get_inodes(inodes); bool match_any = false; for (std::set::iterator i = inodes.begin(); i != inodes.end(); ++i) { if (*i == inode) { match_any = true; break; } } if (!match_any) { return false; } } else { return false; } } /* Filtering by frag and dentry */ if (!frag_dentry.empty() || frag.ino) { EMetaBlob const *metablob = le.get_metablob(); if (metablob) { std::map > dentries; metablob->get_dentries(dentries); if (frag.ino) { bool match_any = false; for (std::map >::iterator i = dentries.begin(); i != dentries.end(); ++i) { if (i->first == frag) { match_any = true; break; } } if (!match_any) { return false; } } if (!frag_dentry.empty()) { bool match_any = false; for (std::map >::iterator i = dentries.begin(); i != dentries.end() && !match_any; ++i) { std::set const &names = i->second; for (std::set::iterator j = names.begin(); j != names.end() && !match_any; ++j) { if (*j == frag_dentry) { match_any = true; } } } if (!match_any) { return false; } } } else { return false; } } /* Filtering by file path */ if (!path_expr.empty()) { EMetaBlob const *metablob = le.get_metablob(); if (metablob) { std::vector paths; metablob->get_paths(paths); bool match_any = false; for (std::vector::iterator p = paths.begin(); p != paths.end(); ++p) { if ((*p).find(path_expr) != std::string::npos) { match_any = true; break; } } if (!match_any) { return false; } } else { return false; } } return true; } int JournalFilter::parse_args( std::vector &argv, std::vector::iterator &arg) { while(arg != argv.end()) { std::string arg_str; if (ceph_argparse_witharg(argv, arg, &arg_str, "--range", (char*)NULL)) { size_t sep_loc = arg_str.find(JournalFilter::range_separator); if (sep_loc == std::string::npos || arg_str.size() <= JournalFilter::range_separator.size()) { derr << "Invalid range '" << arg_str << "'" << dendl; return -EINVAL; } // We have a lower bound if (sep_loc > 0) { std::string range_start_str = arg_str.substr(0, sep_loc); std::string parse_err; range_start = strict_strtoll(range_start_str.c_str(), 0, &parse_err); if (!parse_err.empty()) { derr << "Invalid lower bound '" << range_start_str << "': " << parse_err << dendl; return -EINVAL; } } if (sep_loc < arg_str.size() - JournalFilter::range_separator.size()) { std::string range_end_str = arg_str.substr(sep_loc + range_separator.size()); std::string parse_err; range_end = strict_strtoll(range_end_str.c_str(), 0, &parse_err); if (!parse_err.empty()) { derr << "Invalid upper bound '" << range_end_str << "': " << parse_err << dendl; return -EINVAL; } } } else if (ceph_argparse_witharg(argv, arg, &arg_str, "--path", (char*)NULL)) { dout(4) << "Filtering by path '" << arg_str << "'" << dendl; path_expr = arg_str; } else if (ceph_argparse_witharg(argv, arg, &arg_str, "--inode", (char*)NULL)) { dout(4) << "Filtering by inode '" << arg_str << "'" << dendl; std::string parse_err; inode = strict_strtoll(arg_str.c_str(), 0, &parse_err); if (!parse_err.empty()) { derr << "Invalid inode '" << arg_str << "': " << parse_err << dendl; return -EINVAL; } } else if (ceph_argparse_witharg(argv, arg, &arg_str, "--type", (char*)NULL)) { std::string parse_err; event_type = LogEvent::str_to_type(arg_str); if (event_type == LogEvent::EventType(-1)) { derr << "Invalid event type '" << arg_str << "': " << parse_err << dendl; return -EINVAL; } } else if (ceph_argparse_witharg(argv, arg, &arg_str, "--frag", (char*)NULL)) { std::string const frag_sep = "."; size_t sep_loc = arg_str.find(frag_sep); std::string inode_str; std::string frag_str; if (sep_loc != std::string::npos) { inode_str = arg_str.substr(0, sep_loc); frag_str = arg_str.substr(sep_loc + 1); } else { inode_str = arg_str; frag_str = "0"; } std::string parse_err; inodeno_t frag_ino = strict_strtoll(inode_str.c_str(), 0, &parse_err); if (!parse_err.empty()) { derr << "Invalid inode '" << inode_str << "': " << parse_err << dendl; return -EINVAL; } uint32_t frag_enc = strict_strtoll(frag_str.c_str(), 0, &parse_err); if (!parse_err.empty()) { derr << "Invalid frag '" << frag_str << "': " << parse_err << dendl; return -EINVAL; } frag = dirfrag_t(frag_ino, frag_t(frag_enc)); dout(4) << "dirfrag filter: '" << frag << "'" << dendl; } else if (ceph_argparse_witharg(argv, arg, &arg_str, "--dname", (char*)NULL)) { frag_dentry = arg_str; dout(4) << "dentry filter: '" << frag_dentry << "'" << dendl; } else if (ceph_argparse_witharg(argv, arg, &arg_str, "--client", (char*)NULL)) { std::string parse_err; int64_t client_num = strict_strtoll(arg_str.c_str(), 0, &parse_err); if (!parse_err.empty()) { derr << "Invalid client number " << arg_str << dendl; return -EINVAL; } client_name = entity_name_t::CLIENT(client_num); } else { // We're done with args the filter understands break; } } return 0; } /** * If the filter params are only range, then return * true and set start & end. Else return false. * * Use this to discover if the user has requested a contiguous range * rather than any per-event filtering. */ bool JournalFilter::get_range(uint64_t &start, uint64_t &end) const { if (!path_expr.empty() || inode != 0 || event_type != 0 || frag.ino != 0 || client_name.num() != 0 || (range_start == 0 && range_end == (uint64_t)(-1))) { return false; } else { start = range_start; end = range_end; return true; } }