diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 8ea11b1a2e23..8bf60250309e 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -539,6 +539,9 @@ void ceph_destroy_inode(struct inode *inode) ceph_queue_caps_release(inode); + if (__ceph_has_any_quota(ci)) + ceph_adjust_quota_realms_count(inode, false); + /* * we may still have a snap_realm reference if there are stray * caps in i_snap_caps. @@ -796,8 +799,7 @@ static int fill_inode(struct inode *inode, struct page *locked_page, inode->i_rdev = le32_to_cpu(info->rdev); inode->i_blkbits = fls(le32_to_cpu(info->layout.fl_stripe_unit)) - 1; - ci->i_max_bytes = iinfo->max_bytes; - ci->i_max_files = iinfo->max_files; + __ceph_update_quota(ci, iinfo->max_bytes, iinfo->max_files); if ((new_version || (new_issued & CEPH_CAP_AUTH_SHARED)) && (issued & CEPH_CAP_AUTH_EXCL) == 0) { diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 1c9877c1149f..5ece2e6ad154 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -3609,6 +3609,7 @@ int ceph_mdsc_init(struct ceph_fs_client *fsc) atomic_set(&mdsc->num_sessions, 0); mdsc->max_sessions = 0; mdsc->stopping = 0; + atomic64_set(&mdsc->quotarealms_count, 0); mdsc->last_snap_seq = 0; init_rwsem(&mdsc->snap_rwsem); mdsc->snap_realms = RB_ROOT; diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index 2a67c8b01ae6..2ec3b5b35067 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -314,6 +314,8 @@ struct ceph_mds_client { int max_sessions; /* len of s_mds_sessions */ int stopping; /* true if shutting down */ + atomic64_t quotarealms_count; /* # realms with quota */ + /* * snap_rwsem will cover cap linkage into snaprealms, and * realm snap contexts. (later, we can do per-realm snap diff --git a/fs/ceph/quota.c b/fs/ceph/quota.c index c561a85ea8b1..588744b4665f 100644 --- a/fs/ceph/quota.c +++ b/fs/ceph/quota.c @@ -21,9 +21,19 @@ #include "super.h" #include "mds_client.h" -static inline bool ceph_has_quota(struct ceph_inode_info *ci) +void ceph_adjust_quota_realms_count(struct inode *inode, bool inc) { - return (ci && (ci->i_max_files || ci->i_max_bytes)); + struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc; + if (inc) + atomic64_inc(&mdsc->quotarealms_count); + else + atomic64_dec(&mdsc->quotarealms_count); +} + +static inline bool ceph_has_realms_with_quotas(struct inode *inode) +{ + struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc; + return atomic64_read(&mdsc->quotarealms_count) > 0; } void ceph_handle_quota(struct ceph_mds_client *mdsc, @@ -62,8 +72,8 @@ void ceph_handle_quota(struct ceph_mds_client *mdsc, ci->i_rbytes = le64_to_cpu(h->rbytes); ci->i_rfiles = le64_to_cpu(h->rfiles); ci->i_rsubdirs = le64_to_cpu(h->rsubdirs); - ci->i_max_bytes = le64_to_cpu(h->max_bytes); - ci->i_max_files = le64_to_cpu(h->max_files); + __ceph_update_quota(ci, le64_to_cpu(h->max_bytes), + le64_to_cpu(h->max_files)); spin_unlock(&ci->i_ceph_lock); iput(inode); @@ -103,7 +113,7 @@ static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc, break; ci = ceph_inode(in); - has_quota = ceph_has_quota(ci); + has_quota = __ceph_has_any_quota(ci); iput(in); next = realm->parent; @@ -241,6 +251,9 @@ static bool check_quota_exceeded(struct inode *inode, enum quota_check_op op, */ bool ceph_quota_is_max_files_exceeded(struct inode *inode) { + if (!ceph_has_realms_with_quotas(inode)) + return false; + WARN_ON(!S_ISDIR(inode->i_mode)); return check_quota_exceeded(inode, QUOTA_CHECK_MAX_FILES_OP, 0); @@ -258,6 +271,9 @@ bool ceph_quota_is_max_bytes_exceeded(struct inode *inode, loff_t newsize) { loff_t size = i_size_read(inode); + if (!ceph_has_realms_with_quotas(inode)) + return false; + /* return immediately if we're decreasing file size */ if (newsize <= size) return false; @@ -277,6 +293,9 @@ bool ceph_quota_is_max_bytes_approaching(struct inode *inode, loff_t newsize) { loff_t size = ceph_inode(inode)->i_reported_size; + if (!ceph_has_realms_with_quotas(inode)) + return false; + /* return immediately if we're decreasing file size */ if (newsize <= size) return false; diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 8217abf46182..1321a6749953 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -1075,6 +1075,26 @@ extern int ceph_fs_debugfs_init(struct ceph_fs_client *client); extern void ceph_fs_debugfs_cleanup(struct ceph_fs_client *client); /* quota.c */ +static inline bool __ceph_has_any_quota(struct ceph_inode_info *ci) +{ + return ci->i_max_files || ci->i_max_bytes; +} + +extern void ceph_adjust_quota_realms_count(struct inode *inode, bool inc); + +static inline void __ceph_update_quota(struct ceph_inode_info *ci, + u64 max_bytes, u64 max_files) +{ + bool had_quota, has_quota; + had_quota = __ceph_has_any_quota(ci); + ci->i_max_bytes = max_bytes; + ci->i_max_files = max_files; + has_quota = __ceph_has_any_quota(ci); + + if (had_quota != has_quota) + ceph_adjust_quota_realms_count(&ci->vfs_inode, has_quota); +} + extern void ceph_handle_quota(struct ceph_mds_client *mdsc, struct ceph_mds_session *session, struct ceph_msg *msg);