From 0827bb79ea5127e6763f6e904dfa1a3266046ffb Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Tue, 9 Dec 2014 14:12:08 +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 d67172ae643c..a85b63580eed 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -158,12 +158,14 @@ Client::Client(Messenger *m, MonClient *mc) timer(m->cct, client_lock), callback_handle(NULL), switch_interrupt_cb(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), interrupt_finisher(m->cct), + remount_finisher(m->cct), objecter_finisher(m->cct), tick_event(NULL), monclient(mc), messenger(m), whoami(m->get_myname().num()), @@ -461,6 +463,12 @@ void Client::shutdown() interrupt_finisher.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(); @@ -3275,18 +3283,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) @@ -3318,14 +3330,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; @@ -7601,6 +7606,7 @@ void Client::ll_register_callbacks(struct client_callback_args *args) << " invalidate_dentry_cb " << args->dentry_cb << " getgroups_cb" << args->getgroups_cb << " switch_interrupt_cb " << args->switch_intr_cb + << " remount_cb " << args->remount_cb << dendl; callback_handle = args->handle; if (args->ino_cb) { @@ -7615,6 +7621,10 @@ void Client::ll_register_callbacks(struct client_callback_args *args) switch_interrupt_cb = args->switch_intr_cb; interrupt_finisher.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 8d00037324f2..d8b355c5c5c1 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -136,6 +136,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); typedef void(*client_switch_interrupt_callback_t)(void *req, void *data); @@ -145,6 +146,7 @@ struct client_callback_args { client_ino_callback_t ino_cb; client_dentry_callback_t dentry_cb; client_switch_interrupt_callback_t switch_intr_cb; + client_remount_callback_t remount_cb; client_getgroups_callback_t getgroups_cb; }; @@ -236,6 +238,7 @@ class Client : public Dispatcher { void *callback_handle; client_switch_interrupt_callback_t switch_interrupt_cb; + 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; @@ -243,6 +246,7 @@ class Client : public Dispatcher { Finisher async_ino_invalidator; Finisher async_dentry_invalidator; Finisher interrupt_finisher; + Finisher remount_finisher; Finisher objecter_finisher; Context *tick_event; diff --git a/src/client/fuse_ll.cc b/src/client/fuse_ll.cc index 1f4353057208..6503e9510336 100644 --- a/src/client/fuse_ll.cc +++ b/src/client/fuse_ll.cc @@ -755,6 +755,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; @@ -944,6 +954,7 @@ int CephFuse::Handle::start() ino_cb: client->cct->_conf->fuse_use_invalidate_cb ? ino_invalidate_cb : NULL, dentry_cb: dentry_invalidate_cb, switch_intr_cb: switch_interrupt_cb, + remount_cb: remount_cb, /* * this is broken: * -- 2.47.3