]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
Client: support using dentry invalidation callbacks on older kernels
authorGreg Farnum <gfarnum@redhat.com>
Thu, 26 Feb 2015 23:12:47 +0000 (15:12 -0800)
committerGreg Farnum <gfarnum@redhat.com>
Thu, 26 Feb 2015 23:23:21 +0000 (15:23 -0800)
This brings back a few small code chunks that were removed in
0827bb79ea5127e6763f6e904dfa1a3266046ffb. We check the kernel version,
and if it is less than 3.18 we use these dentry invalidation callbacks
instead of the remount callback. This should resolve a number of
issues with racing against remount, including #10916, and lets older
unprivileged users on older kernels run even if they can't apply
options on mount (#10542).

Signed-off-by: Greg Farnum <gfarnum@redhat.com>
src/client/Client.cc
src/client/Client.h
src/common/config_opts.h

index 837b90cfe6ded14a1131c44700e8796ecacedfbd..4548ca9f1a83acb7428210d41c08e24e3e22742e 100644 (file)
@@ -164,6 +164,7 @@ Client::Client(Messenger *m, MonClient *mc)
     ino_invalidate_cb(NULL),
     dentry_invalidate_cb(NULL),
     getgroups_cb(NULL),
+    can_invalidate_dentries(false),
     require_remount(false),
     async_ino_invalidator(m->cct),
     async_dentry_invalidator(m->cct),
@@ -3459,10 +3460,18 @@ public:
 
 void Client::_invalidate_kernel_dcache()
 {
-  // Hacky:
-  // when remounting a file system, linux kernel trims all unused dentries in the file system
-  if (remount_cb)
+  if (can_invalidate_dentries && dentry_invalidate_cb && root->dir) {
+    for (ceph::unordered_map<string, Dentry*>::iterator p = root->dir->dentries.begin();
+        p != root->dir->dentries.end();
+        ++p) {
+      if (p->second->inode)
+       _schedule_invalidate_dentry_callback(p->second, false);
+    }
+  } else if (remount_cb) {
+    // Hacky:
+    // when remounting a file system, linux kernel trims all unused dentries in the fs
     remount_finisher.queue(new C_Client_Remount(this));
+  }
 }
 
 void Client::trim_caps(MetaSession *s, int max)
@@ -3494,6 +3503,13 @@ void Client::trim_caps(MetaSession *s, int max)
       while (q != in->dn_set.end()) {
        Dentry *dn = *q++;
        if (dn->lru_is_expireable()) {
+         if (can_invalidate_dentries &&
+             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;
@@ -7995,11 +8011,17 @@ void Client::ll_register_callbacks(struct client_callback_args *args)
   getgroups_cb = args->getgroups_cb;
 }
 
-int Client::test_remount()
+int Client::test_dentry_handling(bool can_invalidate)
 {
   int r = 0;
 
-  if (remount_cb) {
+  can_invalidate_dentries = can_invalidate;
+
+  if (can_invalidate_dentries) {
+    assert(dentry_invalidate_cb);
+    ldout(cct, 1) << "using dentry_invalidate_cb" << dendl;
+  } 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"
@@ -8009,6 +8031,10 @@ int Client::test_remount()
       require_remount = true;
       r = s;
     }
+  } 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;
 }
index 121d178df80ca5c54aad245e5c0664a947d71014..fda445798920ba91984e0297028abafb59a85602 100644 (file)
@@ -242,6 +242,7 @@ class Client : public Dispatcher {
   client_ino_callback_t ino_invalidate_cb;
   client_dentry_callback_t dentry_invalidate_cb;
   client_getgroups_callback_t getgroups_cb;
+  bool can_invalidate_dentries;
   bool require_remount;
 
   Finisher async_ino_invalidator;
@@ -955,7 +956,7 @@ public:
   int ll_osdaddr(int osd, char* buf, size_t size);
 
   void ll_register_callbacks(struct client_callback_args *args);
-  int test_remount();
+  int test_dentry_handling(bool can_invalidate);
 };
 
 #endif
index 38416ae1691e3fc453e6ab02f10f087bf1eb0c19..d9380ed06b41938df54b043ba04e21e390b8bb5d 100644 (file)
@@ -326,6 +326,7 @@ OPTION(fuse_big_writes, OPT_BOOL, true)
 OPTION(fuse_atomic_o_trunc, OPT_BOOL, true)
 OPTION(fuse_debug, OPT_BOOL, false)
 OPTION(fuse_multithreaded, OPT_BOOL, true)
+OPTION(client_try_dentry_invalidate, OPT_BOOL, true) // 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(crush_location, OPT_STR, "")       // whitespace-separated list of key=value pairs describing crush location