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.
Unified · Split
| @@ -149,6 +149,10 @@ Mount Options · 148 unmodified lines | |||
| 149 | noasyncreaddir | 149 | noasyncreaddir |
| 150 | Do not use the dcache as above for readdir. | 150 | Do not use the dcache as above for readdir. |
| 151 | 151 | ||
| 152 | noquotadf | ||
| 153 | Report overall filesystem usage in statfs instead of using the root | ||
| 154 | directory quota. | ||
| 155 | |||
| 152 | More Information | 156 | More Information |
| 153 | ================ | 157 | ================ |
| 154 | 158 | ||
| @@ -18,6 +18,8 @@ · 17 unmodified lines | |||
| 18 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | 18 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 19 | */ | 19 | */ |
| 20 | 20 | ||
| 21 | #include <linux/statfs.h> | ||
| 22 | |||
| 21 | #include "super.h" | 23 | #include "super.h" |
| 22 | #include "mds_client.h" | 24 | #include "mds_client.h" |
| 23 | 25 | ||
| @@ -303,3 +305,57 @@ bool ceph_quota_is_max_bytes_approaching(struct inode *inode, loff_t newsize) · 279 unmodified lines | |||
| 303 | return check_quota_exceeded(inode, QUOTA_CHECK_MAX_BYTES_APPROACHING_OP, | 305 | return check_quota_exceeded(inode, QUOTA_CHECK_MAX_BYTES_APPROACHING_OP, |
| 304 | (newsize - size)); | 306 | (newsize - size)); |
| 305 | } | 307 | } |
| 308 | |||
| 309 | /* | ||
| 310 | * ceph_quota_update_statfs - if root has quota update statfs with quota status | ||
| 311 | * @fsc: filesystem client instance | ||
| 312 | * @buf: statfs to update | ||
| 313 | * | ||
| 314 | * If the mounted filesystem root has max_bytes quota set, update the filesystem | ||
| 315 | * statistics with the quota status. | ||
| 316 | * | ||
| 317 | * This function returns true if the stats have been updated, false otherwise. | ||
| 318 | */ | ||
| 319 | bool ceph_quota_update_statfs(struct ceph_fs_client *fsc, struct kstatfs *buf) | ||
| 320 | { | ||
| 321 | struct ceph_mds_client *mdsc = fsc->mdsc; | ||
| 322 | struct ceph_inode_info *ci; | ||
| 323 | struct ceph_snap_realm *realm; | ||
| 324 | struct inode *in; | ||
| 325 | u64 total = 0, used, free; | ||
| 326 | bool is_updated = false; | ||
| 327 | |||
| 328 | down_read(&mdsc->snap_rwsem); | ||
| 329 | realm = get_quota_realm(mdsc, d_inode(fsc->sb->s_root)); | ||
| 330 | up_read(&mdsc->snap_rwsem); | ||
| 331 | if (!realm) | ||
| 332 | return false; | ||
| 333 | |||
| 334 | spin_lock(&realm->inodes_with_caps_lock); | ||
| 335 | in = realm->inode ? igrab(realm->inode) : NULL; | ||
| 336 | spin_unlock(&realm->inodes_with_caps_lock); | ||
| 337 | if (in) { | ||
| 338 | ci = ceph_inode(in); | ||
| 339 | spin_lock(&ci->i_ceph_lock); | ||
| 340 | if (ci->i_max_bytes) { | ||
| 341 | total = ci->i_max_bytes >> CEPH_BLOCK_SHIFT; | ||
| 342 | used = ci->i_rbytes >> CEPH_BLOCK_SHIFT; | ||
| 343 | /* It is possible for a quota to be exceeded. | ||
| 344 | * Report 'zero' in that case | ||
| 345 | */ | ||
| 346 | free = total > used ? total - used : 0; | ||
| 347 | } | ||
| 348 | spin_unlock(&ci->i_ceph_lock); | ||
| 349 | if (total) { | ||
| 350 | buf->f_blocks = total; | ||
| 351 | buf->f_bfree = free; | ||
| 352 | buf->f_bavail = free; | ||
| 353 | is_updated = true; | ||
| 354 | } | ||
| 355 | iput(in); | ||
| 356 | } | ||
| 357 | ceph_put_snap_realm(mdsc, realm); | ||
| 358 | |||
| 359 | return is_updated; | ||
| 360 | } | ||
| 361 | |||
| @@ -76,9 +76,18 @@ static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf) · 75 unmodified lines | |||
| 76 | */ | 76 | */ |
| 77 | buf->f_bsize = 1 << CEPH_BLOCK_SHIFT; | 77 | buf->f_bsize = 1 << CEPH_BLOCK_SHIFT; |
| 78 | buf->f_frsize = 1 << CEPH_BLOCK_SHIFT; | 78 | buf->f_frsize = 1 << CEPH_BLOCK_SHIFT; |
| 79 | buf->f_blocks = le64_to_cpu(st.kb) >> (CEPH_BLOCK_SHIFT-10); | 79 | |
| 80 | buf->f_bfree = le64_to_cpu(st.kb_avail) >> (CEPH_BLOCK_SHIFT-10); | 80 | /* |
| 81 | buf->f_bavail = le64_to_cpu(st.kb_avail) >> (CEPH_BLOCK_SHIFT-10); | 81 | * By default use root quota for stats; fallback to overall filesystem |
| 82 | * usage if using 'noquotadf' mount option or if the root dir doesn't | ||
| 83 | * have max_bytes quota set. | ||
| 84 | */ | ||
| 85 | if (ceph_test_mount_opt(fsc, NOQUOTADF) || | ||
| 86 | !ceph_quota_update_statfs(fsc, buf)) { | ||
| 87 | buf->f_blocks = le64_to_cpu(st.kb) >> (CEPH_BLOCK_SHIFT-10); | ||
| 88 | buf->f_bfree = le64_to_cpu(st.kb_avail) >> (CEPH_BLOCK_SHIFT-10); | ||
| 89 | buf->f_bavail = le64_to_cpu(st.kb_avail) >> (CEPH_BLOCK_SHIFT-10); | ||
| 90 | } | ||
| 82 | 91 | ||
| 83 | buf->f_files = le64_to_cpu(st.num_objects); | 92 | buf->f_files = le64_to_cpu(st.num_objects); |
| 84 | buf->f_ffree = -1; | 93 | buf->f_ffree = -1; |
| @@ -151,6 +160,8 @@ enum { · 66 unmodified lines | |||
| 151 | Opt_acl, | 160 | Opt_acl, |
| 152 | #endif | 161 | #endif |
| 153 | Opt_noacl, | 162 | Opt_noacl, |
| 163 | Opt_quotadf, | ||
| 164 | Opt_noquotadf, | ||
| 154 | }; | 165 | }; |
| 155 | 166 | ||
| 156 | static match_table_t fsopt_tokens = { | 167 | static match_table_t fsopt_tokens = { |
| @@ -187,6 +198,8 @@ static match_table_t fsopt_tokens = { · 30 unmodified lines | |||
| 187 | {Opt_acl, "acl"}, | 198 | {Opt_acl, "acl"}, |
| 188 | #endif | 199 | #endif |
| 189 | {Opt_noacl, "noacl"}, | 200 | {Opt_noacl, "noacl"}, |
| 201 | {Opt_quotadf, "quotadf"}, | ||
| 202 | {Opt_noquotadf, "noquotadf"}, | ||
| 190 | {-1, NULL} | 203 | {-1, NULL} |
| 191 | }; | 204 | }; |
| 192 | 205 | ||
| @@ -334,6 +347,12 @@ static int parse_fsopt_token(char *c, void *private) · 141 unmodified lines | |||
| 334 | case Opt_norequire_active_mds: | 347 | case Opt_norequire_active_mds: |
| 335 | fsopt->flags |= CEPH_MOUNT_OPT_MOUNTWAIT; | 348 | fsopt->flags |= CEPH_MOUNT_OPT_MOUNTWAIT; |
| 336 | break; | 349 | break; |
| 350 | case Opt_quotadf: | ||
| 351 | fsopt->flags &= ~CEPH_MOUNT_OPT_NOQUOTADF; | ||
| 352 | break; | ||
| 353 | case Opt_noquotadf: | ||
| 354 | fsopt->flags |= CEPH_MOUNT_OPT_NOQUOTADF; | ||
| 355 | break; | ||
| 337 | #ifdef CONFIG_CEPH_FS_POSIX_ACL | 356 | #ifdef CONFIG_CEPH_FS_POSIX_ACL |
| 338 | case Opt_acl: | 357 | case Opt_acl: |
| 339 | fsopt->sb_flags |= SB_POSIXACL; | 358 | fsopt->sb_flags |= SB_POSIXACL; |
| @@ -520,6 +539,8 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root) · 180 unmodified lines | |||
| 520 | } | 539 | } |
| 521 | if (fsopt->flags & CEPH_MOUNT_OPT_NOPOOLPERM) | 540 | if (fsopt->flags & CEPH_MOUNT_OPT_NOPOOLPERM) |
| 522 | seq_puts(m, ",nopoolperm"); | 541 | seq_puts(m, ",nopoolperm"); |
| 542 | if (fsopt->flags & CEPH_MOUNT_OPT_NOQUOTADF) | ||
| 543 | seq_puts(m, ",noquotadf"); | ||
| 523 | 544 | ||
| 524 | #ifdef CONFIG_CEPH_FS_POSIX_ACL | 545 | #ifdef CONFIG_CEPH_FS_POSIX_ACL |
| 525 | if (fsopt->sb_flags & SB_POSIXACL) | 546 | if (fsopt->sb_flags & SB_POSIXACL) |
| @@ -39,6 +39,7 @@ · 38 unmodified lines | |||
| 39 | #define CEPH_MOUNT_OPT_FSCACHE (1<<10) /* use fscache */ | 39 | #define CEPH_MOUNT_OPT_FSCACHE (1<<10) /* use fscache */ |
| 40 | #define CEPH_MOUNT_OPT_NOPOOLPERM (1<<11) /* no pool permission check */ | 40 | #define CEPH_MOUNT_OPT_NOPOOLPERM (1<<11) /* no pool permission check */ |
| 41 | #define CEPH_MOUNT_OPT_MOUNTWAIT (1<<12) /* mount waits if no mds is up */ | 41 | #define CEPH_MOUNT_OPT_MOUNTWAIT (1<<12) /* mount waits if no mds is up */ |
| 42 | #define CEPH_MOUNT_OPT_NOQUOTADF (1<<13) /* no root dir quota in statfs */ | ||
| 42 | 43 | ||
| 43 | #define CEPH_MOUNT_OPT_DEFAULT CEPH_MOUNT_OPT_DCACHE | 44 | #define CEPH_MOUNT_OPT_DEFAULT CEPH_MOUNT_OPT_DCACHE |
| 44 | 45 | ||
| @@ -1104,5 +1105,7 @@ extern bool ceph_quota_is_max_bytes_exceeded(struct inode *inode, · 1059 unmodified lines | |||
| 1104 | loff_t newlen); | 1105 | loff_t newlen); |
| 1105 | extern bool ceph_quota_is_max_bytes_approaching(struct inode *inode, | 1106 | extern bool ceph_quota_is_max_bytes_approaching(struct inode *inode, |
| 1106 | loff_t newlen); | 1107 | loff_t newlen); |
| 1108 | extern bool ceph_quota_update_statfs(struct ceph_fs_client *fsc, | ||
| 1109 | struct kstatfs *buf); | ||
| 1107 | 1110 | ||
| 1108 | #endif /* _FS_CEPH_SUPER_H */ | 1111 | #endif /* _FS_CEPH_SUPER_H */ |