提交 9122eed5 编写于 作者: L Luis Henriques 提交者: Ilya Dryomov

ceph: quota: report root dir quota usage in statfs

This commit changes statfs default behaviour when reporting usage
statistics.  Instead of using the overall filesystem usage, statfs now
reports the quota for the filesystem root, if ceph.quota.max_bytes has
been set for this inode.  If quota hasn't been set, it falls back to the
old statfs behaviour.

A new mount option is also added ('noquotadf') to disable this behaviour.
Signed-off-by: NLuis Henriques <lhenriques@suse.com>
Reviewed-by: N"Yan, Zheng" <zyan@redhat.com>
Signed-off-by: NIlya Dryomov <idryomov@gmail.com>
上级 d557c48d
...@@ -149,6 +149,10 @@ Mount Options ...@@ -149,6 +149,10 @@ Mount Options
noasyncreaddir noasyncreaddir
Do not use the dcache as above for readdir. Do not use the dcache as above for readdir.
noquotadf
Report overall filesystem usage in statfs instead of using the root
directory quota.
More Information More Information
================ ================
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>. * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/ */
#include <linux/statfs.h>
#include "super.h" #include "super.h"
#include "mds_client.h" #include "mds_client.h"
...@@ -303,3 +305,57 @@ bool ceph_quota_is_max_bytes_approaching(struct inode *inode, loff_t newsize) ...@@ -303,3 +305,57 @@ bool ceph_quota_is_max_bytes_approaching(struct inode *inode, loff_t newsize)
return check_quota_exceeded(inode, QUOTA_CHECK_MAX_BYTES_APPROACHING_OP, return check_quota_exceeded(inode, QUOTA_CHECK_MAX_BYTES_APPROACHING_OP,
(newsize - size)); (newsize - size));
} }
/*
* ceph_quota_update_statfs - if root has quota update statfs with quota status
* @fsc: filesystem client instance
* @buf: statfs to update
*
* If the mounted filesystem root has max_bytes quota set, update the filesystem
* statistics with the quota status.
*
* This function returns true if the stats have been updated, false otherwise.
*/
bool ceph_quota_update_statfs(struct ceph_fs_client *fsc, struct kstatfs *buf)
{
struct ceph_mds_client *mdsc = fsc->mdsc;
struct ceph_inode_info *ci;
struct ceph_snap_realm *realm;
struct inode *in;
u64 total = 0, used, free;
bool is_updated = false;
down_read(&mdsc->snap_rwsem);
realm = get_quota_realm(mdsc, d_inode(fsc->sb->s_root));
up_read(&mdsc->snap_rwsem);
if (!realm)
return false;
spin_lock(&realm->inodes_with_caps_lock);
in = realm->inode ? igrab(realm->inode) : NULL;
spin_unlock(&realm->inodes_with_caps_lock);
if (in) {
ci = ceph_inode(in);
spin_lock(&ci->i_ceph_lock);
if (ci->i_max_bytes) {
total = ci->i_max_bytes >> CEPH_BLOCK_SHIFT;
used = ci->i_rbytes >> CEPH_BLOCK_SHIFT;
/* It is possible for a quota to be exceeded.
* Report 'zero' in that case
*/
free = total > used ? total - used : 0;
}
spin_unlock(&ci->i_ceph_lock);
if (total) {
buf->f_blocks = total;
buf->f_bfree = free;
buf->f_bavail = free;
is_updated = true;
}
iput(in);
}
ceph_put_snap_realm(mdsc, realm);
return is_updated;
}
...@@ -76,9 +76,18 @@ static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf) ...@@ -76,9 +76,18 @@ static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf)
*/ */
buf->f_bsize = 1 << CEPH_BLOCK_SHIFT; buf->f_bsize = 1 << CEPH_BLOCK_SHIFT;
buf->f_frsize = 1 << CEPH_BLOCK_SHIFT; buf->f_frsize = 1 << CEPH_BLOCK_SHIFT;
buf->f_blocks = le64_to_cpu(st.kb) >> (CEPH_BLOCK_SHIFT-10);
buf->f_bfree = le64_to_cpu(st.kb_avail) >> (CEPH_BLOCK_SHIFT-10); /*
buf->f_bavail = le64_to_cpu(st.kb_avail) >> (CEPH_BLOCK_SHIFT-10); * By default use root quota for stats; fallback to overall filesystem
* usage if using 'noquotadf' mount option or if the root dir doesn't
* have max_bytes quota set.
*/
if (ceph_test_mount_opt(fsc, NOQUOTADF) ||
!ceph_quota_update_statfs(fsc, buf)) {
buf->f_blocks = le64_to_cpu(st.kb) >> (CEPH_BLOCK_SHIFT-10);
buf->f_bfree = le64_to_cpu(st.kb_avail) >> (CEPH_BLOCK_SHIFT-10);
buf->f_bavail = le64_to_cpu(st.kb_avail) >> (CEPH_BLOCK_SHIFT-10);
}
buf->f_files = le64_to_cpu(st.num_objects); buf->f_files = le64_to_cpu(st.num_objects);
buf->f_ffree = -1; buf->f_ffree = -1;
...@@ -151,6 +160,8 @@ enum { ...@@ -151,6 +160,8 @@ enum {
Opt_acl, Opt_acl,
#endif #endif
Opt_noacl, Opt_noacl,
Opt_quotadf,
Opt_noquotadf,
}; };
static match_table_t fsopt_tokens = { static match_table_t fsopt_tokens = {
...@@ -187,6 +198,8 @@ static match_table_t fsopt_tokens = { ...@@ -187,6 +198,8 @@ static match_table_t fsopt_tokens = {
{Opt_acl, "acl"}, {Opt_acl, "acl"},
#endif #endif
{Opt_noacl, "noacl"}, {Opt_noacl, "noacl"},
{Opt_quotadf, "quotadf"},
{Opt_noquotadf, "noquotadf"},
{-1, NULL} {-1, NULL}
}; };
...@@ -334,6 +347,12 @@ static int parse_fsopt_token(char *c, void *private) ...@@ -334,6 +347,12 @@ static int parse_fsopt_token(char *c, void *private)
case Opt_norequire_active_mds: case Opt_norequire_active_mds:
fsopt->flags |= CEPH_MOUNT_OPT_MOUNTWAIT; fsopt->flags |= CEPH_MOUNT_OPT_MOUNTWAIT;
break; break;
case Opt_quotadf:
fsopt->flags &= ~CEPH_MOUNT_OPT_NOQUOTADF;
break;
case Opt_noquotadf:
fsopt->flags |= CEPH_MOUNT_OPT_NOQUOTADF;
break;
#ifdef CONFIG_CEPH_FS_POSIX_ACL #ifdef CONFIG_CEPH_FS_POSIX_ACL
case Opt_acl: case Opt_acl:
fsopt->sb_flags |= SB_POSIXACL; fsopt->sb_flags |= SB_POSIXACL;
...@@ -520,6 +539,8 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root) ...@@ -520,6 +539,8 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root)
} }
if (fsopt->flags & CEPH_MOUNT_OPT_NOPOOLPERM) if (fsopt->flags & CEPH_MOUNT_OPT_NOPOOLPERM)
seq_puts(m, ",nopoolperm"); seq_puts(m, ",nopoolperm");
if (fsopt->flags & CEPH_MOUNT_OPT_NOQUOTADF)
seq_puts(m, ",noquotadf");
#ifdef CONFIG_CEPH_FS_POSIX_ACL #ifdef CONFIG_CEPH_FS_POSIX_ACL
if (fsopt->sb_flags & SB_POSIXACL) if (fsopt->sb_flags & SB_POSIXACL)
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#define CEPH_MOUNT_OPT_FSCACHE (1<<10) /* use fscache */ #define CEPH_MOUNT_OPT_FSCACHE (1<<10) /* use fscache */
#define CEPH_MOUNT_OPT_NOPOOLPERM (1<<11) /* no pool permission check */ #define CEPH_MOUNT_OPT_NOPOOLPERM (1<<11) /* no pool permission check */
#define CEPH_MOUNT_OPT_MOUNTWAIT (1<<12) /* mount waits if no mds is up */ #define CEPH_MOUNT_OPT_MOUNTWAIT (1<<12) /* mount waits if no mds is up */
#define CEPH_MOUNT_OPT_NOQUOTADF (1<<13) /* no root dir quota in statfs */
#define CEPH_MOUNT_OPT_DEFAULT CEPH_MOUNT_OPT_DCACHE #define CEPH_MOUNT_OPT_DEFAULT CEPH_MOUNT_OPT_DCACHE
...@@ -1104,5 +1105,7 @@ extern bool ceph_quota_is_max_bytes_exceeded(struct inode *inode, ...@@ -1104,5 +1105,7 @@ extern bool ceph_quota_is_max_bytes_exceeded(struct inode *inode,
loff_t newlen); loff_t newlen);
extern bool ceph_quota_is_max_bytes_approaching(struct inode *inode, extern bool ceph_quota_is_max_bytes_approaching(struct inode *inode,
loff_t newlen); loff_t newlen);
extern bool ceph_quota_update_statfs(struct ceph_fs_client *fsc,
struct kstatfs *buf);
#endif /* _FS_CEPH_SUPER_H */ #endif /* _FS_CEPH_SUPER_H */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册