From 0cb65d53e61bd39a7518a7d814c7f9447327daaf Mon Sep 17 00:00:00 2001 From: Luis Henriques Date: Fri, 5 Jan 2018 10:47:21 +0000 Subject: [PATCH] ceph: quota: support for ceph.quota.max_bytes BugLink: https://bugs.launchpad.net/bugs/1834235 Signed-off-by: Luis Henriques Reviewed-by: "Yan, Zheng" Signed-off-by: Ilya Dryomov (cherry picked from commit 2b83845f8bd711e66e1c367a9bd56c9df3410236) Signed-off-by: Connor Kuehl Acked-by: Kleber Sacilotto de Souza Acked-by: Stefan Bader Signed-off-by: Kleber Sacilotto de Souza --- fs/ceph/file.c | 11 +++++++++++ fs/ceph/inode.c | 4 ++++ fs/ceph/quota.c | 28 +++++++++++++++++++++++++++- fs/ceph/super.h | 2 ++ 4 files changed, 44 insertions(+), 1 deletion(-) diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 4ef0d60b4ebe..a51098c0fc87 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -1340,6 +1340,11 @@ retry_snap: pos = iocb->ki_pos; count = iov_iter_count(from); + if (ceph_quota_is_max_bytes_exceeded(inode, pos + count)) { + err = -EDQUOT; + goto out; + } + err = file_remove_privs(file); if (err) goto out; @@ -1670,6 +1675,12 @@ static long ceph_fallocate(struct file *file, int mode, goto unlock; } + if (!(mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE)) && + ceph_quota_is_max_bytes_exceeded(inode, offset + length)) { + ret = -EDQUOT; + goto unlock; + } + if (ceph_osdmap_flag(osdc, CEPH_OSDMAP_FULL) && !(mode & FALLOC_FL_PUNCH_HOLE)) { ret = -ENOSPC; diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index ae6723e80c71..80aad584e2a0 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -2150,6 +2150,10 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) if (err != 0) return err; + if ((attr->ia_valid & ATTR_SIZE) && + ceph_quota_is_max_bytes_exceeded(inode, attr->ia_size)) + return -EDQUOT; + err = __ceph_setattr(inode, attr); if (err >= 0 && (attr->ia_valid & ATTR_MODE)) diff --git a/fs/ceph/quota.c b/fs/ceph/quota.c index fd27e7113731..e324593a9771 100644 --- a/fs/ceph/quota.c +++ b/fs/ceph/quota.c @@ -136,7 +136,8 @@ bool ceph_quota_is_same_realm(struct inode *old, struct inode *new) } enum quota_check_op { - QUOTA_CHECK_MAX_FILES_OP /* check quota max_files limit */ + QUOTA_CHECK_MAX_FILES_OP, /* check quota max_files limit */ + QUOTA_CHECK_MAX_BYTES_OP /* check quota max_files limit */ }; /* @@ -172,12 +173,18 @@ static bool check_quota_exceeded(struct inode *inode, enum quota_check_op op, if (op == QUOTA_CHECK_MAX_FILES_OP) { max = ci->i_max_files; rvalue = ci->i_rfiles + ci->i_rsubdirs; + } else { + max = ci->i_max_bytes; + rvalue = ci->i_rbytes; } spin_unlock(&ci->i_ceph_lock); switch (op) { case QUOTA_CHECK_MAX_FILES_OP: exceeded = (max && (rvalue >= max)); break; + case QUOTA_CHECK_MAX_BYTES_OP: + exceeded = (max && (rvalue + delta > max)); + break; default: /* Shouldn't happen */ pr_warn("Invalid quota check op (%d)\n", op); @@ -212,3 +219,22 @@ bool ceph_quota_is_max_files_exceeded(struct inode *inode) return check_quota_exceeded(inode, QUOTA_CHECK_MAX_FILES_OP, 0); } + +/* + * ceph_quota_is_max_bytes_exceeded - check if we can write to a file + * @inode: inode being written + * @newsize: new size if write succeeds + * + * This functions returns true is max_bytes quota allows a file size to reach + * @newsize; it returns false otherwise. + */ +bool ceph_quota_is_max_bytes_exceeded(struct inode *inode, loff_t newsize) +{ + loff_t size = i_size_read(inode); + + /* return immediately if we're decreasing file size */ + if (newsize <= size) + return false; + + return check_quota_exceeded(inode, QUOTA_CHECK_MAX_BYTES_OP, (newsize - size)); +} diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 54e7f2ed8963..fb1119147a68 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -1080,5 +1080,7 @@ extern void ceph_handle_quota(struct ceph_mds_client *mdsc, struct ceph_msg *msg); extern bool ceph_quota_is_max_files_exceeded(struct inode *inode); extern bool ceph_quota_is_same_realm(struct inode *old, struct inode *new); +extern bool ceph_quota_is_max_bytes_exceeded(struct inode *inode, + loff_t newlen); #endif /* _FS_CEPH_SUPER_H */ -- 2.39.2