From b6d2b6d1a51969c210ae75fef93c71ac21f511a6 Mon Sep 17 00:00:00 2001 From: John Spray Date: Wed, 11 May 2016 13:18:23 +0100 Subject: [PATCH] client: report root's quota in statfs 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 --- doc/cephfs/client-auth.rst | 19 +++++++++++++++ src/client/Client.cc | 48 +++++++++++++++++++++++++++----------- src/common/config_opts.h | 1 + 3 files changed, 54 insertions(+), 14 deletions(-) diff --git a/doc/cephfs/client-auth.rst b/doc/cephfs/client-auth.rst index 30017c3f2c2..dac40eda809 100644 --- a/doc/cephfs/client-auth.rst +++ b/doc/cephfs/client-auth.rst @@ -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 =============== diff --git a/src/client/Client.cc b/src/client/Client.cc index 7fcd907bc68..f2d9c4fdd08 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -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; } diff --git a/src/common/config_opts.h b/src/common/config_opts.h index 67d729ce337..c25c7fc0fdc 100644 --- a/src/common/config_opts.h +++ b/src/common/config_opts.h @@ -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)