ceph: quota: support for ceph.quota.max_bytes
authorLuis Henriques <lhenriques@suse.com>
Fri, 5 Jan 2018 10:47:21 +0000 (10:47 +0000)
committerIlya Dryomov <idryomov@gmail.com>
Mon, 2 Apr 2018 09:17:52 +0000 (11:17 +0200)
Signed-off-by: Luis Henriques <lhenriques@suse.com>
Reviewed-by: "Yan, Zheng" <zyan@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
fs/ceph/file.c
fs/ceph/inode.c
fs/ceph/quota.c
fs/ceph/super.h

index c3042330e0e97de9ee37dcff4693b8feb7f4c0d8..0a2843fdebbd23b9047f15e6967df0432e4d87ff 100644 (file)
@@ -1378,6 +1378,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;
@@ -1708,6 +1713,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;
index 2c6f8be4ed630979f4bbdab8fe8cbb4f5a94c1ca..50ccae151ea08ace51c4d3869d3920b0b2be8a6d 100644 (file)
@@ -2147,6 +2147,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))
index 5d7dada91a572cc7aab8f24e62a3a7d63b2562e8..745f9f47027b542244038d217f6c5b011c655e58 100644 (file)
@@ -134,7 +134,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 */
 };
 
 /*
@@ -171,6 +172,9 @@ 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;
                }
                is_root = (ci->i_vino.ino == CEPH_INO_ROOT);
                spin_unlock(&ci->i_ceph_lock);
@@ -178,6 +182,9 @@ static bool check_quota_exceeded(struct inode *inode, enum quota_check_op 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));
+}
index eea6f70f3bf95308e53503326efb2a106321152e..5870c225c2fcb14c9e3412a0a59390fdc7729663 100644 (file)
@@ -1079,5 +1079,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 */