Fixes: http://tracker.ceph.com/issues/22269
Signed-off-by: Patrick Donnelly <pdonnell@redhat.com>
(cherry picked from commit
5b2b1d14468c290c56ee6c95ea557c99464e0098)
Conflicts:
PendingReleaseNotes - put the release note under 10.2.11
src/ceph_fuse.cc - changed order of client_try_dentry_invalidate and
can_invalidate_dentries assignments to match master, and use jewel
form of g_conf for accessing config option values
src/client/Client.cc - code being replaced by _do_remount() calls is
different in jewel, and use jewel convention for accessing config
option values
src/common/legacy_config_opts.h - file does not exist in jewel
src/common/options.cc - file does not exit in jewel; made the changes
manually in src/common/config_opts.h
delete workload, it can lead to high latency when leveldb's
single-threaded compaction cannot keep up. rocksdb supports multiple
threads for compaction, which avoids this problem.
+
+* The CephFS client now catches failures to clear dentries during startup
+ and refuses to start as consistency and untrimmable cache issues may
+ develop. The new option client_die_on_failed_dentry_invalidate (default:
+ true) may be turned off to allow the client to proceed (dangerous!).
+
#if defined(__linux__)
int ver = get_linux_version();
assert(ver != 0);
- bool can_invalidate_dentries = g_conf->client_try_dentry_invalidate &&
- ver < KERNEL_VERSION(3, 18, 0);
+ bool client_try_dentry_invalidate = g_conf->client_try_dentry_invalidate;
+ bool can_invalidate_dentries =
+ client_try_dentry_invalidate && ver < KERNEL_VERSION(3, 18, 0);
int tr = client->test_dentry_handling(can_invalidate_dentries);
- if (tr != 0) {
+ bool client_die_on_failed_dentry_invalidate = g_conf->client_die_on_failed_dentry_invalidate;
+ if (tr != 0 && client_die_on_failed_dentry_invalidate) {
cerr << "ceph-fuse[" << getpid()
<< "]: fuse failed dentry invalidate/remount test with error "
<< cpp_strerror(tr) << ", stopping" << std::endl;
getgroups_cb(NULL),
umask_cb(NULL),
can_invalidate_dentries(false),
- require_remount(false),
async_ino_invalidator(m->cct),
async_dentry_invalidator(m->cct),
interrupt_finisher(m->cct),
sync_cond.Signal();
}
+int Client::_do_remount(void)
+{
+ errno = 0;
+ int r = remount_cb(callback_handle);
+ if (r != 0) {
+ int e = errno;
+ client_t whoami = get_nodeid();
+ if (r == -1) {
+ lderr(cct) <<
+ "failed to remount (to trim kernel dentries): "
+ "errno = " << e << " (" << strerror(e) << ")" << dendl;
+ } else {
+ lderr(cct) <<
+ "failed to remount (to trim kernel dentries): "
+ "return code = " << r << dendl;
+ }
+ bool should_abort = cct->_conf->client_die_on_failed_remount ||
+ cct->_conf->client_die_on_failed_dentry_invalidate;
+ if (should_abort && !unmounting) {
+ lderr(cct) << "failed to remount for kernel dentry trimming; quitting!" << dendl;
+ ceph_abort();
+ }
+ }
+ return r;
+}
+
class C_Client_Remount : public Context {
private:
Client *client;
explicit C_Client_Remount(Client *c) : client(c) {}
void finish(int r) {
assert (r == 0);
- r = client->remount_cb(client->callback_handle);
- if (r != 0) {
- client_t whoami = client->get_nodeid();
- lderr(client->cct) << "tried to remount (to trim kernel dentries) and got error "
- << r << dendl;
- if (client->require_remount && !client->unmounting) {
- assert(0 == "failed to remount for kernel dentry trimming");
- }
- }
+ client->_do_remount();
}
};
if (can_invalidate_dentries) {
assert(dentry_invalidate_cb);
ldout(cct, 1) << "using dentry_invalidate_cb" << dendl;
+ r = 0;
} else if (remount_cb) {
ldout(cct, 1) << "using remount_cb" << dendl;
- int s = remount_cb(callback_handle);
- if (s) {
- lderr(cct) << "Failed to invoke remount, needed to ensure kernel dcache consistency"
- << dendl;
- }
- if (cct->_conf->client_die_on_failed_remount) {
- require_remount = true;
- r = s;
+ r = _do_remount();
+ }
+ if (r) {
+ bool should_abort = cct->_conf->client_die_on_failed_dentry_invalidate;
+ if (should_abort) {
+ lderr(cct) << "no method to invalidate kernel dentry cache; quitting!" << dendl;
+ ceph_abort();
+ } else {
+ lderr(cct) << "no method to invalidate kernel dentry cache; expect issues!" << dendl;
}
- } else {
- lderr(cct) << "no method to invalidate kernel dentry cache; expect issues!" << dendl;
- if (cct->_conf->client_die_on_failed_remount)
- assert(0);
}
return r;
}
client_getgroups_callback_t getgroups_cb;
client_umask_callback_t umask_cb;
bool can_invalidate_dentries;
- bool require_remount;
Finisher async_ino_invalidator;
Finisher async_dentry_invalidator;
int _release_fh(Fh *fh);
void _put_fh(Fh *fh);
+ int _do_remount(void);
+ friend class C_Client_Remount;
struct C_Readahead : public Context {
Client *client;
OPTION(fuse_syncfs_on_mksnap, OPT_BOOL, true)
OPTION(client_try_dentry_invalidate, OPT_BOOL, false) // the client should try to use dentry invaldation instead of remounting, on kernels it believes that will work for
-OPTION(client_die_on_failed_remount, OPT_BOOL, true)
+OPTION(client_die_on_failed_remount, OPT_BOOL, false)
+OPTION(client_die_on_failed_dentry_invalidate, OPT_BOOL, true)
OPTION(client_check_pool_perm, OPT_BOOL, true)
OPTION(client_use_faked_inos, OPT_BOOL, false)
OPTION(client_mds_namespace, OPT_INT, -1)