diff options
| -rw-r--r-- | fs/ceph/file.c | 6 | ||||
| -rw-r--r-- | fs/ceph/quota.c | 38 | ||||
| -rw-r--r-- | fs/ceph/super.h | 2 |
3 files changed, 45 insertions, 1 deletions
diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 0a2843fdebbd..f85040d73e3d 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c | |||
| @@ -1464,6 +1464,7 @@ retry_snap: | |||
| 1464 | 1464 | ||
| 1465 | if (written >= 0) { | 1465 | if (written >= 0) { |
| 1466 | int dirty; | 1466 | int dirty; |
| 1467 | |||
| 1467 | spin_lock(&ci->i_ceph_lock); | 1468 | spin_lock(&ci->i_ceph_lock); |
| 1468 | ci->i_inline_version = CEPH_INLINE_NONE; | 1469 | ci->i_inline_version = CEPH_INLINE_NONE; |
| 1469 | dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR, | 1470 | dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR, |
| @@ -1471,6 +1472,8 @@ retry_snap: | |||
| 1471 | spin_unlock(&ci->i_ceph_lock); | 1472 | spin_unlock(&ci->i_ceph_lock); |
| 1472 | if (dirty) | 1473 | if (dirty) |
| 1473 | __mark_inode_dirty(inode, dirty); | 1474 | __mark_inode_dirty(inode, dirty); |
| 1475 | if (ceph_quota_is_max_bytes_approaching(inode, iocb->ki_pos)) | ||
| 1476 | ceph_check_caps(ci, CHECK_CAPS_NODELAY, NULL); | ||
| 1474 | } | 1477 | } |
| 1475 | 1478 | ||
| 1476 | dout("aio_write %p %llx.%llx %llu~%u dropping cap refs on %s\n", | 1479 | dout("aio_write %p %llx.%llx %llu~%u dropping cap refs on %s\n", |
| @@ -1767,6 +1770,9 @@ static long ceph_fallocate(struct file *file, int mode, | |||
| 1767 | spin_unlock(&ci->i_ceph_lock); | 1770 | spin_unlock(&ci->i_ceph_lock); |
| 1768 | if (dirty) | 1771 | if (dirty) |
| 1769 | __mark_inode_dirty(inode, dirty); | 1772 | __mark_inode_dirty(inode, dirty); |
| 1773 | if ((endoff > size) && | ||
| 1774 | ceph_quota_is_max_bytes_approaching(inode, endoff)) | ||
| 1775 | ceph_check_caps(ci, CHECK_CAPS_NODELAY, NULL); | ||
| 1770 | } | 1776 | } |
| 1771 | 1777 | ||
| 1772 | ceph_put_cap_refs(ci, got); | 1778 | ceph_put_cap_refs(ci, got); |
diff --git a/fs/ceph/quota.c b/fs/ceph/quota.c index 745f9f47027b..7d1e18e2249f 100644 --- a/fs/ceph/quota.c +++ b/fs/ceph/quota.c | |||
| @@ -135,7 +135,9 @@ bool ceph_quota_is_same_realm(struct inode *old, struct inode *new) | |||
| 135 | 135 | ||
| 136 | enum quota_check_op { | 136 | enum 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 | QUOTA_CHECK_MAX_BYTES_OP, /* check quota max_files limit */ |
| 139 | QUOTA_CHECK_MAX_BYTES_APPROACHING_OP /* check if quota max_files | ||
| 140 | limit is approaching */ | ||
| 139 | }; | 141 | }; |
| 140 | 142 | ||
| 141 | /* | 143 | /* |
| @@ -185,6 +187,20 @@ static bool check_quota_exceeded(struct inode *inode, enum quota_check_op op, | |||
| 185 | case QUOTA_CHECK_MAX_BYTES_OP: | 187 | case QUOTA_CHECK_MAX_BYTES_OP: |
| 186 | exceeded = (max && (rvalue + delta > max)); | 188 | exceeded = (max && (rvalue + delta > max)); |
| 187 | break; | 189 | break; |
| 190 | case QUOTA_CHECK_MAX_BYTES_APPROACHING_OP: | ||
| 191 | if (max) { | ||
| 192 | if (rvalue >= max) | ||
| 193 | exceeded = true; | ||
| 194 | else { | ||
| 195 | /* | ||
| 196 | * when we're writing more that 1/16th | ||
| 197 | * of the available space | ||
| 198 | */ | ||
| 199 | exceeded = | ||
| 200 | (((max - rvalue) >> 4) < delta); | ||
| 201 | } | ||
| 202 | } | ||
| 203 | break; | ||
| 188 | default: | 204 | default: |
| 189 | /* Shouldn't happen */ | 205 | /* Shouldn't happen */ |
| 190 | pr_warn("Invalid quota check op (%d)\n", op); | 206 | pr_warn("Invalid quota check op (%d)\n", op); |
| @@ -238,3 +254,23 @@ bool ceph_quota_is_max_bytes_exceeded(struct inode *inode, loff_t newsize) | |||
| 238 | 254 | ||
| 239 | return check_quota_exceeded(inode, QUOTA_CHECK_MAX_BYTES_OP, (newsize - size)); | 255 | return check_quota_exceeded(inode, QUOTA_CHECK_MAX_BYTES_OP, (newsize - size)); |
| 240 | } | 256 | } |
| 257 | |||
| 258 | /* | ||
| 259 | * ceph_quota_is_max_bytes_approaching - check if we're reaching max_bytes | ||
| 260 | * @inode: inode being written | ||
| 261 | * @newsize: new size if write succeeds | ||
| 262 | * | ||
| 263 | * This function returns true if the new file size @newsize will be consuming | ||
| 264 | * more than 1/16th of the available quota space; it returns false otherwise. | ||
| 265 | */ | ||
| 266 | bool ceph_quota_is_max_bytes_approaching(struct inode *inode, loff_t newsize) | ||
| 267 | { | ||
| 268 | loff_t size = ceph_inode(inode)->i_reported_size; | ||
| 269 | |||
| 270 | /* return immediately if we're decreasing file size */ | ||
| 271 | if (newsize <= size) | ||
| 272 | return false; | ||
| 273 | |||
| 274 | return check_quota_exceeded(inode, QUOTA_CHECK_MAX_BYTES_APPROACHING_OP, | ||
| 275 | (newsize - size)); | ||
| 276 | } | ||
diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 5870c225c2fc..e4ff485d24c7 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h | |||
| @@ -1081,5 +1081,7 @@ extern bool ceph_quota_is_max_files_exceeded(struct inode *inode); | |||
| 1081 | extern bool ceph_quota_is_same_realm(struct inode *old, struct inode *new); | 1081 | extern bool ceph_quota_is_same_realm(struct inode *old, struct inode *new); |
| 1082 | extern bool ceph_quota_is_max_bytes_exceeded(struct inode *inode, | 1082 | extern bool ceph_quota_is_max_bytes_exceeded(struct inode *inode, |
| 1083 | loff_t newlen); | 1083 | loff_t newlen); |
| 1084 | extern bool ceph_quota_is_max_bytes_approaching(struct inode *inode, | ||
| 1085 | loff_t newlen); | ||
| 1084 | 1086 | ||
| 1085 | #endif /* _FS_CEPH_SUPER_H */ | 1087 | #endif /* _FS_CEPH_SUPER_H */ |
