From d1257436fdf79bad5fe0719a6be71e2abb2d2462 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Wed, 17 Dec 2014 15:59:44 +0800 Subject: [PATCH] client: use remount to trim kernel dcache when remounting a file system, linux kernel trims all unused dentry in the file system. Fixes: #10277 Signed-off-by: Yan, Zheng --- src/client/Client.cc | 44 ++++++++++++++++++++++++++----------------- src/client/Client.h | 4 ++++ src/client/fuse_ll.cc | 11 +++++++++++ 3 files changed, 42 insertions(+), 17 deletions(-) diff --git a/src/client/Client.cc b/src/client/Client.cc index a258a37720315..8377dc8095a6f 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -156,11 +156,13 @@ Client::Client(Messenger *m, MonClient *mc) m_command_hook(this), timer(m->cct, client_lock), callback_handle(NULL), + remount_cb(NULL), ino_invalidate_cb(NULL), dentry_invalidate_cb(NULL), getgroups_cb(NULL), async_ino_invalidator(m->cct), async_dentry_invalidator(m->cct), + remount_finisher(m->cct), objecter_finisher(m->cct), tick_event(NULL), monclient(mc), messenger(m), whoami(m->get_myname().num()), @@ -451,6 +453,12 @@ void Client::shutdown() async_dentry_invalidator.stop(); } + if (remount_cb) { + ldout(cct, 10) << "shutdown stopping remount finisher" << dendl; + remount_finisher.wait_for_empty(); + remount_finisher.stop(); + } + objectcacher->stop(); // outside of client_lock! this does a join. client_lock.Lock(); @@ -3228,18 +3236,22 @@ void Client::remove_session_caps(MetaSession *s) sync_cond.Signal(); } +class C_Client_Remount : public Context { +private: + Client *client; +public: + C_Client_Remount(Client *c) : client(c) {} + void finish(int r) { + client->remount_cb(client->callback_handle); + } +}; + void Client::_invalidate_kernel_dcache() { - // notify kernel to invalidate top level directory entries. As a side effect, - // unused inodes underneath these entries get pruned. - if (dentry_invalidate_cb && root->dir) { - for (ceph::unordered_map::iterator p = root->dir->dentries.begin(); - p != root->dir->dentries.end(); - ++p) { - if (p->second->inode) - _schedule_invalidate_dentry_callback(p->second, false); - } - } + // Hacky: + // when remounting a file system, linux kernel trims all unused dentries in the file system + if (remount_cb) + remount_finisher.queue(new C_Client_Remount(this)); } void Client::trim_caps(MetaSession *s, int max) @@ -3271,14 +3283,7 @@ void Client::trim_caps(MetaSession *s, int max) while (q != in->dn_set.end()) { Dentry *dn = *q++; if (dn->lru_is_expireable()) { - if (dn->dir->parent_inode->ino == MDS_INO_ROOT) { - // Only issue one of these per DN for inodes in root: handle - // others more efficiently by calling for root-child DNs at - // the end of this function. - _schedule_invalidate_dentry_callback(dn, true); - } trim_dentry(dn); - } else { ldout(cct, 20) << " not expirable: " << dn->name << dendl; all = false; @@ -7072,6 +7077,7 @@ void Client::ll_register_callbacks(struct client_callback_args *args) << " invalidate_ino_cb " << args->ino_cb << " invalidate_dentry_cb " << args->dentry_cb << " getgroups_cb" << args->getgroups_cb + << " remount_cb " << args->remount_cb << dendl; callback_handle = args->handle; if (args->ino_cb) { @@ -7082,6 +7088,10 @@ void Client::ll_register_callbacks(struct client_callback_args *args) dentry_invalidate_cb = args->dentry_cb; async_dentry_invalidator.start(); } + if (args->remount_cb) { + remount_cb = args->remount_cb; + remount_finisher.start(); + } getgroups_cb = args->getgroups_cb; } diff --git a/src/client/Client.h b/src/client/Client.h index 41212779c0a70..b46d945467ac1 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -124,6 +124,7 @@ typedef void (*client_ino_callback_t)(void *handle, vinodeno_t ino, int64_t off, typedef void (*client_dentry_callback_t)(void *handle, vinodeno_t dirino, vinodeno_t ino, string& name); +typedef void (*client_remount_callback_t)(void *handle); typedef int (*client_getgroups_callback_t)(void *handle, uid_t uid, gid_t **sgids); @@ -131,6 +132,7 @@ struct client_callback_args { void *handle; client_ino_callback_t ino_cb; client_dentry_callback_t dentry_cb; + client_remount_callback_t remount_cb; client_getgroups_callback_t getgroups_cb; }; @@ -221,12 +223,14 @@ class Client : public Dispatcher { SafeTimer timer; void *callback_handle; + client_remount_callback_t remount_cb; client_ino_callback_t ino_invalidate_cb; client_dentry_callback_t dentry_invalidate_cb; client_getgroups_callback_t getgroups_cb; Finisher async_ino_invalidator; Finisher async_dentry_invalidator; + Finisher remount_finisher; Finisher objecter_finisher; Context *tick_event; diff --git a/src/client/fuse_ll.cc b/src/client/fuse_ll.cc index 891bc32fb7610..276e608df6998 100644 --- a/src/client/fuse_ll.cc +++ b/src/client/fuse_ll.cc @@ -692,6 +692,16 @@ static void dentry_invalidate_cb(void *handle, vinodeno_t dirino, #endif } +static void remount_cb(void *handle) +{ + // used for trimming kernel dcache. when remounting a file system, linux kernel + // trims all unused dentries in the file system + char cmd[1024]; + CephFuse::Handle *cfuse = (CephFuse::Handle *)handle; + snprintf(cmd, sizeof(cmd), "mount -i -o remount %s", cfuse->mountpoint); + system(cmd); +} + static void do_init(void *data, fuse_conn_info *bar) { CephFuse::Handle *cfuse = (CephFuse::Handle *)data; @@ -877,6 +887,7 @@ int CephFuse::Handle::start() handle: this, ino_cb: client->cct->_conf->fuse_use_invalidate_cb ? ino_invalidate_cb : NULL, dentry_cb: dentry_invalidate_cb, + remount_cb: remount_cb, /* * this is broken: * -- 2.39.5