]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
client: report root's quota in statfs 8747/head
authorJohn Spray <john.spray@redhat.com>
Wed, 11 May 2016 12:18:23 +0000 (13:18 +0100)
committerJohn Spray <john.spray@redhat.com>
Tue, 17 May 2016 12:08:13 +0000 (13:08 +0100)
When user is mounted a quota-restricted inode
as the root, report that inode's quota status
as the filesystem statistics in statfs.

This allows us to have a fairly convincing illusion
that someone has a filesystem to themselves, when
they're really mounting a restricted part of
the larger global filesystem.

Fixes: http://tracker.ceph.com/issues/15599
Signed-off-by: John Spray <john.spray@redhat.com>
doc/cephfs/client-auth.rst
src/client/Client.cc
src/common/config_opts.h

index 30017c3f2c203f515bbfb61fb32e2b9ee96ce628..dac40eda8094b62f091451453e396f4c08ef0d42 100644 (file)
@@ -43,6 +43,25 @@ for example, to restrict client ``foo`` to ``mnt/bar`` directory, we will use. :
 
 ./ceph-fuse -n client.foo mnt -r /bar
 
+Free space reporting
+--------------------
+
+By default, when a client is mounting a sub-directory, the used space (``df``)
+will be calculated from the quota on that sub-directory, rather than reporting
+the overall amount of space used on the cluster.
+
+If you would like the client to report the overall usage of the filesystem,
+and not just the quota usage on the sub-directory mounted, then set the
+following config option on the client:
+
+::
+
+    client quota df = false
+
+If quotas are not enabled, or no quota is set on the sub-directory mounted,
+then the overall usage of the filesystem will be reported irrespective of
+the value of this setting.
+
 OSD restriction
 ===============
 
index 7fcd907bc6898df80b1fe8760b64f2e27633cbf7..f2d9c4fdd0877d23d4f5897887dd5968f39a40de 100644 (file)
@@ -8752,19 +8752,11 @@ int Client::statfs(const char *path, struct statvfs *stbuf)
   tout(cct) << "statfs" << std::endl;
 
   ceph_statfs stats;
-
-  Mutex lock("Client::statfs::lock");
-  Cond cond;
-  bool done;
-  int rval;
-
-  objecter->get_fs_stats(stats, new C_SafeCond(&lock, &cond, &done, &rval));
+  C_SaferCond cond;
+  objecter->get_fs_stats(stats, &cond);
 
   client_lock.Unlock();
-  lock.Lock();
-  while (!done)
-    cond.Wait(lock);
-  lock.Unlock();
+  int rval = cond.wait();
   client_lock.Lock();
 
   memset(stbuf, 0, sizeof(*stbuf));
@@ -8779,9 +8771,6 @@ int Client::statfs(const char *path, struct statvfs *stbuf)
   const int CEPH_BLOCK_SHIFT = 22;
   stbuf->f_frsize = 1 << CEPH_BLOCK_SHIFT;
   stbuf->f_bsize = 1 << CEPH_BLOCK_SHIFT;
-  stbuf->f_blocks = stats.kb >> (CEPH_BLOCK_SHIFT - 10);
-  stbuf->f_bfree = stats.kb_avail >> (CEPH_BLOCK_SHIFT - 10);
-  stbuf->f_bavail = stats.kb_avail >> (CEPH_BLOCK_SHIFT - 10);
   stbuf->f_files = stats.num_objects;
   stbuf->f_ffree = -1;
   stbuf->f_favail = -1;
@@ -8789,6 +8778,37 @@ int Client::statfs(const char *path, struct statvfs *stbuf)
   stbuf->f_flag = 0;        // ??
   stbuf->f_namemax = NAME_MAX;
 
+  // Usually quota_root will == root_ancestor, but if the mount root has no
+  // quota but we can see a parent of it that does have a quota, we'll
+  // respect that one instead.
+  assert(root != nullptr);
+  Inode *quota_root = get_quota_root(root);
+
+  // get_quota_root should always give us something if client quotas are
+  // enabled
+  assert(cct->_conf->client_quota == false || quota_root != nullptr);
+
+  if (quota_root && cct->_conf->client_quota_df && quota_root->quota.max_bytes) {
+    // Special case: if there is a size quota set on the Inode acting
+    // as the root for this client mount, then report the quota status
+    // as the filesystem statistics.
+    const fsblkcnt_t total = quota_root->quota.max_bytes >> CEPH_BLOCK_SHIFT;
+    const fsblkcnt_t used = quota_root->rstat.rbytes >> CEPH_BLOCK_SHIFT;
+    const fsblkcnt_t free = total - used;
+
+
+    stbuf->f_blocks = total;
+    stbuf->f_bfree = free;
+    stbuf->f_bavail = free;
+  } else {
+    // General case: report the overall RADOS cluster's statistics.  Because
+    // multiple pools may be used without one filesystem namespace via
+    // layouts, this is the most correct thing we can do.
+    stbuf->f_blocks = stats.kb >> (CEPH_BLOCK_SHIFT - 10);
+    stbuf->f_bfree = stats.kb_avail >> (CEPH_BLOCK_SHIFT - 10);
+    stbuf->f_bavail = stats.kb_avail >> (CEPH_BLOCK_SHIFT - 10);
+  }
+
   return rval;
 }
 
index 67d729ce3370620c0692bc7378b1ac00a6ffb336..c25c7fc0fdce619ea34f8dd43c430aef11cd2e5a 100644 (file)
@@ -382,6 +382,7 @@ OPTION(client_notify_timeout, OPT_INT, 10) // in seconds
 OPTION(osd_client_watch_timeout, OPT_INT, 30) // in seconds
 OPTION(client_caps_release_delay, OPT_INT, 5) // in seconds
 OPTION(client_quota, OPT_BOOL, false)
+OPTION(client_quota_df, OPT_BOOL, true) // use quota for df on subdir mounts
 OPTION(client_oc, OPT_BOOL, true)
 OPTION(client_oc_size, OPT_INT, 1024*1024* 200)    // MB * n
 OPTION(client_oc_max_dirty, OPT_INT, 1024*1024* 100)    // MB * n  (dirty OR tx.. bigish)