summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLuis Henriques <lhenriques@suse.com>2018-01-05 05:47:21 -0500
committerIlya Dryomov <idryomov@gmail.com>2018-04-02 05:17:52 -0400
commit2b83845f8bd711e66e1c367a9bd56c9df3410236 (patch)
treeb2f750e237d72cc4bd2ffe80ef427ac4116d40e3 /fs
parentcafe21a4fb3075fb2980caba8fdb533a1bdb52b0 (diff)
ceph: quota: support for ceph.quota.max_bytes
Signed-off-by: Luis Henriques <lhenriques@suse.com> Reviewed-by: "Yan, Zheng" <zyan@redhat.com> Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/ceph/file.c11
-rw-r--r--fs/ceph/inode.c4
-rw-r--r--fs/ceph/quota.c28
-rw-r--r--fs/ceph/super.h2
4 files changed, 44 insertions, 1 deletions
diff --git a/fs/ceph/file.c b/fs/ceph/file.c
index c3042330e0e9..0a2843fdebbd 100644
--- a/fs/ceph/file.c
+++ b/fs/ceph/file.c
@@ -1378,6 +1378,11 @@ retry_snap:
1378 1378
1379 pos = iocb->ki_pos; 1379 pos = iocb->ki_pos;
1380 count = iov_iter_count(from); 1380 count = iov_iter_count(from);
1381 if (ceph_quota_is_max_bytes_exceeded(inode, pos + count)) {
1382 err = -EDQUOT;
1383 goto out;
1384 }
1385
1381 err = file_remove_privs(file); 1386 err = file_remove_privs(file);
1382 if (err) 1387 if (err)
1383 goto out; 1388 goto out;
@@ -1708,6 +1713,12 @@ static long ceph_fallocate(struct file *file, int mode,
1708 goto unlock; 1713 goto unlock;
1709 } 1714 }
1710 1715
1716 if (!(mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE)) &&
1717 ceph_quota_is_max_bytes_exceeded(inode, offset + length)) {
1718 ret = -EDQUOT;
1719 goto unlock;
1720 }
1721
1711 if (ceph_osdmap_flag(osdc, CEPH_OSDMAP_FULL) && 1722 if (ceph_osdmap_flag(osdc, CEPH_OSDMAP_FULL) &&
1712 !(mode & FALLOC_FL_PUNCH_HOLE)) { 1723 !(mode & FALLOC_FL_PUNCH_HOLE)) {
1713 ret = -ENOSPC; 1724 ret = -ENOSPC;
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index 2c6f8be4ed63..50ccae151ea0 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -2147,6 +2147,10 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
2147 if (err != 0) 2147 if (err != 0)
2148 return err; 2148 return err;
2149 2149
2150 if ((attr->ia_valid & ATTR_SIZE) &&
2151 ceph_quota_is_max_bytes_exceeded(inode, attr->ia_size))
2152 return -EDQUOT;
2153
2150 err = __ceph_setattr(inode, attr); 2154 err = __ceph_setattr(inode, attr);
2151 2155
2152 if (err >= 0 && (attr->ia_valid & ATTR_MODE)) 2156 if (err >= 0 && (attr->ia_valid & ATTR_MODE))
diff --git a/fs/ceph/quota.c b/fs/ceph/quota.c
index 5d7dada91a57..745f9f47027b 100644
--- a/fs/ceph/quota.c
+++ b/fs/ceph/quota.c
@@ -134,7 +134,8 @@ bool ceph_quota_is_same_realm(struct inode *old, struct inode *new)
134} 134}
135 135
136enum quota_check_op { 136enum quota_check_op {
137 QUOTA_CHECK_MAX_FILES_OP /* check quota max_files limit */ 137 QUOTA_CHECK_MAX_FILES_OP, /* check quota max_files limit */
138 QUOTA_CHECK_MAX_BYTES_OP /* check quota max_files limit */
138}; 139};
139 140
140/* 141/*
@@ -171,6 +172,9 @@ static bool check_quota_exceeded(struct inode *inode, enum quota_check_op op,
171 if (op == QUOTA_CHECK_MAX_FILES_OP) { 172 if (op == QUOTA_CHECK_MAX_FILES_OP) {
172 max = ci->i_max_files; 173 max = ci->i_max_files;
173 rvalue = ci->i_rfiles + ci->i_rsubdirs; 174 rvalue = ci->i_rfiles + ci->i_rsubdirs;
175 } else {
176 max = ci->i_max_bytes;
177 rvalue = ci->i_rbytes;
174 } 178 }
175 is_root = (ci->i_vino.ino == CEPH_INO_ROOT); 179 is_root = (ci->i_vino.ino == CEPH_INO_ROOT);
176 spin_unlock(&ci->i_ceph_lock); 180 spin_unlock(&ci->i_ceph_lock);
@@ -178,6 +182,9 @@ static bool check_quota_exceeded(struct inode *inode, enum quota_check_op op,
178 case QUOTA_CHECK_MAX_FILES_OP: 182 case QUOTA_CHECK_MAX_FILES_OP:
179 exceeded = (max && (rvalue >= max)); 183 exceeded = (max && (rvalue >= max));
180 break; 184 break;
185 case QUOTA_CHECK_MAX_BYTES_OP:
186 exceeded = (max && (rvalue + delta > max));
187 break;
181 default: 188 default:
182 /* Shouldn't happen */ 189 /* Shouldn't happen */
183 pr_warn("Invalid quota check op (%d)\n", op); 190 pr_warn("Invalid quota check op (%d)\n", op);
@@ -212,3 +219,22 @@ bool ceph_quota_is_max_files_exceeded(struct inode *inode)
212 219
213 return check_quota_exceeded(inode, QUOTA_CHECK_MAX_FILES_OP, 0); 220 return check_quota_exceeded(inode, QUOTA_CHECK_MAX_FILES_OP, 0);
214} 221}
222
223/*
224 * ceph_quota_is_max_bytes_exceeded - check if we can write to a file
225 * @inode: inode being written
226 * @newsize: new size if write succeeds
227 *
228 * This functions returns true is max_bytes quota allows a file size to reach
229 * @newsize; it returns false otherwise.
230 */
231bool ceph_quota_is_max_bytes_exceeded(struct inode *inode, loff_t newsize)
232{
233 loff_t size = i_size_read(inode);
234
235 /* return immediately if we're decreasing file size */
236 if (newsize <= size)
237 return false;
238
239 return check_quota_exceeded(inode, QUOTA_CHECK_MAX_BYTES_OP, (newsize - size));
240}
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
index eea6f70f3bf9..5870c225c2fc 100644
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -1079,5 +1079,7 @@ extern void ceph_handle_quota(struct ceph_mds_client *mdsc,
1079 struct ceph_msg *msg); 1079 struct ceph_msg *msg);
1080extern bool ceph_quota_is_max_files_exceeded(struct inode *inode); 1080extern bool ceph_quota_is_max_files_exceeded(struct inode *inode);
1081extern bool ceph_quota_is_same_realm(struct inode *old, struct inode *new); 1081extern bool ceph_quota_is_same_realm(struct inode *old, struct inode *new);
1082extern bool ceph_quota_is_max_bytes_exceeded(struct inode *inode,
1083 loff_t newlen);
1082 1084
1083#endif /* _FS_CEPH_SUPER_H */ 1085#endif /* _FS_CEPH_SUPER_H */