This will be used in testing repair.
Signed-off-by: Samuel Just <sam.just@inktank.com>
// Tests index failure paths
OPTION(filestore_index_retry_probability, OPT_DOUBLE, 0)
+// Allow object read error injection
+OPTION(filestore_debug_inject_read_err, OPT_BOOL, false)
+
OPTION(filestore_debug_omap_check, OPT_BOOL, 0) // Expensive debugging check on sync
// Use omap for xattrs for attrs over
OPTION(filestore_xattr_use_omap, OPT_BOOL, false)
assert(!m_filestore_fail_eio || r != -EIO);
return r;
}
+ if (g_conf->filestore_debug_inject_read_err) {
+ debug_delete_obj(o);
+ }
} else {
/* Ensure that replay of this op doesn't result in the object_map
* going away.
g_conf->filestore_op_thread_suicide_timeout, &op_tp),
flusher_queue_len(0), flusher_thread(this),
logger(NULL),
+ read_error_lock("FileStore::read_error_lock"),
m_filestore_btrfs_clone_range(g_conf->filestore_btrfs_clone_range),
m_filestore_btrfs_snap (g_conf->filestore_btrfs_snap ),
m_filestore_commit_timeout(g_conf->filestore_commit_timeout),
<< " = " << r
<< " (size " << st->st_size << ")" << dendl;
}
- return r;
+ if (g_conf->filestore_debug_inject_read_err &&
+ debug_mdata_eio(oid)) {
+ return -EIO;
+ } else {
+ return r;
+ }
}
int FileStore::read(coll_t cid, const hobject_t& oid,
dout(10) << "FileStore::read " << cid << "/" << oid << " " << offset << "~"
<< got << "/" << len << dendl;
- return got;
+ if (g_conf->filestore_debug_inject_read_err &&
+ debug_data_eio(oid)) {
+ return -EIO;
+ } else {
+ return got;
+ }
}
int FileStore::fiemap(coll_t cid, const hobject_t& oid,
return 0;
}
+// debug EIO injection
+void FileStore::inject_data_error(const hobject_t &oid) {
+ Mutex::Locker l(read_error_lock);
+ dout(10) << __func__ << ": init error on " << oid << dendl;
+ data_error_set.insert(oid);
+}
+void FileStore::inject_mdata_error(const hobject_t &oid) {
+ Mutex::Locker l(read_error_lock);
+ dout(10) << __func__ << ": init error on " << oid << dendl;
+ mdata_error_set.insert(oid);
+}
+void FileStore::debug_delete_obj(const hobject_t &oid) {
+ Mutex::Locker l(read_error_lock);
+ dout(10) << __func__ << ": clear error on " << oid << dendl;
+ data_error_set.erase(oid);
+ mdata_error_set.erase(oid);
+}
+bool FileStore::debug_data_eio(const hobject_t &oid) {
+ Mutex::Locker l(read_error_lock);
+ if (data_error_set.count(oid)) {
+ dout(10) << __func__ << ": inject error on " << oid << dendl;
+ return true;
+ } else {
+ return false;
+ }
+}
+bool FileStore::debug_mdata_eio(const hobject_t &oid) {
+ Mutex::Locker l(read_error_lock);
+ if (mdata_error_set.count(oid)) {
+ dout(10) << __func__ << ": inject error on " << oid << dendl;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
// objects
int FileStore::getattr(coll_t cid, const hobject_t& oid, const char *name, bufferptr &bp)
out:
dout(10) << "getattr " << cid << "/" << oid << " '" << name << "' = " << r << dendl;
assert(!m_filestore_fail_eio || r != -EIO);
- return r;
+ if (g_conf->filestore_debug_inject_read_err &&
+ debug_mdata_eio(oid)) {
+ return -EIO;
+ } else {
+ return r;
+ }
}
int FileStore::getattrs(coll_t cid, const hobject_t& oid, map<string,bufferptr>& aset, bool user_only)
out:
dout(10) << "getattrs " << cid << "/" << oid << " = " << r << dendl;
assert(!m_filestore_fail_eio || r != -EIO);
- return r;
+
+ if (g_conf->filestore_debug_inject_read_err &&
+ debug_mdata_eio(oid)) {
+ return -EIO;
+ } else {
+ return r;
+ }
}
int FileStore::_setattrs(coll_t cid, const hobject_t& oid, map<string,bufferptr>& aset,
}
uuid_d get_fsid() { return fsid; }
+ // DEBUG read error injection, an object is removed from both on delete()
+ Mutex read_error_lock;
+ set<hobject_t> data_error_set; // read() will return -EIO
+ set<hobject_t> mdata_error_set; // getattr(),stat() will return -EIO
+ void inject_data_error(const hobject_t &oid);
+ void inject_mdata_error(const hobject_t &oid);
+ void debug_delete_obj(const hobject_t &oid);
+ bool debug_data_eio(const hobject_t &oid);
+ bool debug_mdata_eio(const hobject_t &oid);
+
int snapshot(const string& name);
// attrs
virtual void set_fsid(uuid_d u) = 0;
virtual uuid_d get_fsid() = 0;
+
+ // DEBUG
+ virtual void inject_data_error(const hobject_t &oid) {}
+ virtual void inject_mdata_error(const hobject_t &oid) {}
};
r = admin_socket->register_command("getomap", test_ops_hook,
"getomap <pool-id> <obj-name>");
assert(r == 0);
+ r = admin_socket->register_command("truncobj", test_ops_hook,
+ "truncobj <pool-id> <obj-name> <len>");
+ assert(r == 0);
+
+ r = admin_socket->register_command("injectdataerr", test_ops_hook,
+ "injectdataerr <pool-id> <obj-name>");
+ assert(r == 0);
+
+ r = admin_socket->register_command("injectmdataerr", test_ops_hook,
+ "injectmdataerr <pool-id> <obj-name>");
+ assert(r == 0);
service.init();
service.publish_map(osdmap);
cct->get_admin_socket()->unregister_command("rmomapkey");
cct->get_admin_socket()->unregister_command("setomapheader");
cct->get_admin_socket()->unregister_command("getomap");
+ cct->get_admin_socket()->unregister_command("truncobj");
+ cct->get_admin_socket()->unregister_command("injectdataerr");
+ cct->get_admin_socket()->unregister_command("injectmdataerr");
delete test_ops_hook;
test_ops_hook = NULL;
// setomapval <pool-id> <obj-name> <key> <val>
// rmomapkey <pool-id> <obj-name> <key>
// setomapheader <pool-id> <obj-name> <header>
+// truncobj <pool-id> <obj-name> <newlen>
void TestOpsSocketHook::test_ops(OSDService *service, ObjectStore *store,
std::string command, std::string args, ostream &ss)
{
//Support changing the omap on a single osd by using the Admin Socket to
//directly request the osd make a change.
if (command == "setomapval" || command == "rmomapkey" ||
- command == "setomapheader" || command == "getomap") {
+ command == "setomapheader" || command == "getomap" ||
+ command == "truncobj" || command == "injectmdataerr" ||
+ command == "injectdataerr"
+ ) {
std::vector<std::string> argv;
pg_t rawpg, pgid;
int64_t pool;
} else {
ss << "error=" << r;
}
+ } else if (command == "truncobj") {
+ if (argc != 4) {
+ ss << "usage: truncobj <pool> <obj-name> <val>";
+ return;
+ }
+ t.truncate(coll_t(pgid), obj, atoi(argv[3].c_str()));
+ r = store->apply_transaction(t);
+ if (r < 0)
+ ss << "error=" << r;
+ else
+ ss << "ok";
+ } else if (command == "injectdataerr") {
+ store->inject_data_error(obj);
+ ss << "ok";
+ } else if (command == "injectmdataerr") {
+ store->inject_mdata_error(obj);
+ ss << "ok";
}
return;
}