xref: /openbmc/linux/fs/ceph/quota.c (revision 71f2cc64)
1fb18a575SLuis Henriques // SPDX-License-Identifier: GPL-2.0
2fb18a575SLuis Henriques /*
3fb18a575SLuis Henriques  * quota.c - CephFS quota
4fb18a575SLuis Henriques  *
5fb18a575SLuis Henriques  * Copyright (C) 2017-2018 SUSE
6fb18a575SLuis Henriques  *
7fb18a575SLuis Henriques  * This program is free software; you can redistribute it and/or
8fb18a575SLuis Henriques  * modify it under the terms of the GNU General Public License
9fb18a575SLuis Henriques  * as published by the Free Software Foundation; either version 2
10fb18a575SLuis Henriques  * of the License, or (at your option) any later version.
11fb18a575SLuis Henriques  *
12fb18a575SLuis Henriques  * This program is distributed in the hope that it will be useful,
13fb18a575SLuis Henriques  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14fb18a575SLuis Henriques  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15fb18a575SLuis Henriques  * GNU General Public License for more details.
16fb18a575SLuis Henriques  *
17fb18a575SLuis Henriques  * You should have received a copy of the GNU General Public License
18fb18a575SLuis Henriques  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19fb18a575SLuis Henriques  */
20fb18a575SLuis Henriques 
219122eed5SLuis Henriques #include <linux/statfs.h>
229122eed5SLuis Henriques 
23fb18a575SLuis Henriques #include "super.h"
24fb18a575SLuis Henriques #include "mds_client.h"
25fb18a575SLuis Henriques 
26d557c48dSLuis Henriques void ceph_adjust_quota_realms_count(struct inode *inode, bool inc)
27cafe21a4SLuis Henriques {
28d557c48dSLuis Henriques 	struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
29d557c48dSLuis Henriques 	if (inc)
30d557c48dSLuis Henriques 		atomic64_inc(&mdsc->quotarealms_count);
31d557c48dSLuis Henriques 	else
32d557c48dSLuis Henriques 		atomic64_dec(&mdsc->quotarealms_count);
33d557c48dSLuis Henriques }
34d557c48dSLuis Henriques 
35d557c48dSLuis Henriques static inline bool ceph_has_realms_with_quotas(struct inode *inode)
36d557c48dSLuis Henriques {
37d557c48dSLuis Henriques 	struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
38d557c48dSLuis Henriques 	return atomic64_read(&mdsc->quotarealms_count) > 0;
39cafe21a4SLuis Henriques }
40cafe21a4SLuis Henriques 
41fb18a575SLuis Henriques void ceph_handle_quota(struct ceph_mds_client *mdsc,
42fb18a575SLuis Henriques 		       struct ceph_mds_session *session,
43fb18a575SLuis Henriques 		       struct ceph_msg *msg)
44fb18a575SLuis Henriques {
45fb18a575SLuis Henriques 	struct super_block *sb = mdsc->fsc->sb;
46fb18a575SLuis Henriques 	struct ceph_mds_quota *h = msg->front.iov_base;
47fb18a575SLuis Henriques 	struct ceph_vino vino;
48fb18a575SLuis Henriques 	struct inode *inode;
49fb18a575SLuis Henriques 	struct ceph_inode_info *ci;
50fb18a575SLuis Henriques 
510fcf6c02SYan, Zheng 	if (msg->front.iov_len < sizeof(*h)) {
52fb18a575SLuis Henriques 		pr_err("%s corrupt message mds%d len %d\n", __func__,
53fb18a575SLuis Henriques 		       session->s_mds, (int)msg->front.iov_len);
54fb18a575SLuis Henriques 		ceph_msg_dump(msg);
55fb18a575SLuis Henriques 		return;
56fb18a575SLuis Henriques 	}
57fb18a575SLuis Henriques 
58fb18a575SLuis Henriques 	/* increment msg sequence number */
59fb18a575SLuis Henriques 	mutex_lock(&session->s_mutex);
60fb18a575SLuis Henriques 	session->s_seq++;
61fb18a575SLuis Henriques 	mutex_unlock(&session->s_mutex);
62fb18a575SLuis Henriques 
63fb18a575SLuis Henriques 	/* lookup inode */
64fb18a575SLuis Henriques 	vino.ino = le64_to_cpu(h->ino);
65fb18a575SLuis Henriques 	vino.snap = CEPH_NOSNAP;
66fb18a575SLuis Henriques 	inode = ceph_find_inode(sb, vino);
67fb18a575SLuis Henriques 	if (!inode) {
68fb18a575SLuis Henriques 		pr_warn("Failed to find inode %llu\n", vino.ino);
69fb18a575SLuis Henriques 		return;
70fb18a575SLuis Henriques 	}
71fb18a575SLuis Henriques 	ci = ceph_inode(inode);
72fb18a575SLuis Henriques 
73fb18a575SLuis Henriques 	spin_lock(&ci->i_ceph_lock);
74fb18a575SLuis Henriques 	ci->i_rbytes = le64_to_cpu(h->rbytes);
75fb18a575SLuis Henriques 	ci->i_rfiles = le64_to_cpu(h->rfiles);
76fb18a575SLuis Henriques 	ci->i_rsubdirs = le64_to_cpu(h->rsubdirs);
77d557c48dSLuis Henriques 	__ceph_update_quota(ci, le64_to_cpu(h->max_bytes),
78d557c48dSLuis Henriques 		            le64_to_cpu(h->max_files));
79fb18a575SLuis Henriques 	spin_unlock(&ci->i_ceph_lock);
80fb18a575SLuis Henriques 
81fb18a575SLuis Henriques 	iput(inode);
82fb18a575SLuis Henriques }
83b7a29217SLuis Henriques 
84cafe21a4SLuis Henriques /*
85cafe21a4SLuis Henriques  * This function walks through the snaprealm for an inode and returns the
86cafe21a4SLuis Henriques  * ceph_snap_realm for the first snaprealm that has quotas set (either max_files
87cafe21a4SLuis Henriques  * or max_bytes).  If the root is reached, return the root ceph_snap_realm
88cafe21a4SLuis Henriques  * instead.
89cafe21a4SLuis Henriques  *
90cafe21a4SLuis Henriques  * Note that the caller is responsible for calling ceph_put_snap_realm() on the
91cafe21a4SLuis Henriques  * returned realm.
92cafe21a4SLuis Henriques  */
93cafe21a4SLuis Henriques static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc,
94cafe21a4SLuis Henriques 					       struct inode *inode)
95cafe21a4SLuis Henriques {
96cafe21a4SLuis Henriques 	struct ceph_inode_info *ci = NULL;
97cafe21a4SLuis Henriques 	struct ceph_snap_realm *realm, *next;
98cafe21a4SLuis Henriques 	struct inode *in;
990eb6bbe4SYan, Zheng 	bool has_quota;
100cafe21a4SLuis Henriques 
10125963669SYan, Zheng 	if (ceph_snap(inode) != CEPH_NOSNAP)
10225963669SYan, Zheng 		return NULL;
10325963669SYan, Zheng 
104cafe21a4SLuis Henriques 	realm = ceph_inode(inode)->i_snap_realm;
10525963669SYan, Zheng 	if (realm)
106cafe21a4SLuis Henriques 		ceph_get_snap_realm(mdsc, realm);
10725963669SYan, Zheng 	else
10825963669SYan, Zheng 		pr_err_ratelimited("get_quota_realm: ino (%llx.%llx) "
10925963669SYan, Zheng 				   "null i_snap_realm\n", ceph_vinop(inode));
110cafe21a4SLuis Henriques 	while (realm) {
111e3161f17SLuis Henriques 		spin_lock(&realm->inodes_with_caps_lock);
112e3161f17SLuis Henriques 		in = realm->inode ? igrab(realm->inode) : NULL;
113e3161f17SLuis Henriques 		spin_unlock(&realm->inodes_with_caps_lock);
114e3161f17SLuis Henriques 		if (!in)
115cafe21a4SLuis Henriques 			break;
116e3161f17SLuis Henriques 
117cafe21a4SLuis Henriques 		ci = ceph_inode(in);
118d557c48dSLuis Henriques 		has_quota = __ceph_has_any_quota(ci);
119cafe21a4SLuis Henriques 		iput(in);
1200eb6bbe4SYan, Zheng 
121cafe21a4SLuis Henriques 		next = realm->parent;
1220eb6bbe4SYan, Zheng 		if (has_quota || !next)
1230eb6bbe4SYan, Zheng 		       return realm;
1240eb6bbe4SYan, Zheng 
125cafe21a4SLuis Henriques 		ceph_get_snap_realm(mdsc, next);
126cafe21a4SLuis Henriques 		ceph_put_snap_realm(mdsc, realm);
127cafe21a4SLuis Henriques 		realm = next;
128cafe21a4SLuis Henriques 	}
129cafe21a4SLuis Henriques 	if (realm)
130cafe21a4SLuis Henriques 		ceph_put_snap_realm(mdsc, realm);
131cafe21a4SLuis Henriques 
132cafe21a4SLuis Henriques 	return NULL;
133cafe21a4SLuis Henriques }
134cafe21a4SLuis Henriques 
135cafe21a4SLuis Henriques bool ceph_quota_is_same_realm(struct inode *old, struct inode *new)
136cafe21a4SLuis Henriques {
137cafe21a4SLuis Henriques 	struct ceph_mds_client *mdsc = ceph_inode_to_client(old)->mdsc;
138cafe21a4SLuis Henriques 	struct ceph_snap_realm *old_realm, *new_realm;
139cafe21a4SLuis Henriques 	bool is_same;
140cafe21a4SLuis Henriques 
141cafe21a4SLuis Henriques 	down_read(&mdsc->snap_rwsem);
142cafe21a4SLuis Henriques 	old_realm = get_quota_realm(mdsc, old);
143cafe21a4SLuis Henriques 	new_realm = get_quota_realm(mdsc, new);
144cafe21a4SLuis Henriques 	is_same = (old_realm == new_realm);
145cafe21a4SLuis Henriques 	up_read(&mdsc->snap_rwsem);
146cafe21a4SLuis Henriques 
147cafe21a4SLuis Henriques 	if (old_realm)
148cafe21a4SLuis Henriques 		ceph_put_snap_realm(mdsc, old_realm);
149cafe21a4SLuis Henriques 	if (new_realm)
150cafe21a4SLuis Henriques 		ceph_put_snap_realm(mdsc, new_realm);
151cafe21a4SLuis Henriques 
152cafe21a4SLuis Henriques 	return is_same;
153cafe21a4SLuis Henriques }
154cafe21a4SLuis Henriques 
155b7a29217SLuis Henriques enum quota_check_op {
1562b83845fSLuis Henriques 	QUOTA_CHECK_MAX_FILES_OP,	/* check quota max_files limit */
1571ab302a0SLuis Henriques 	QUOTA_CHECK_MAX_BYTES_OP,	/* check quota max_files limit */
1581ab302a0SLuis Henriques 	QUOTA_CHECK_MAX_BYTES_APPROACHING_OP	/* check if quota max_files
1591ab302a0SLuis Henriques 						   limit is approaching */
160b7a29217SLuis Henriques };
161b7a29217SLuis Henriques 
162b7a29217SLuis Henriques /*
163b7a29217SLuis Henriques  * check_quota_exceeded() will walk up the snaprealm hierarchy and, for each
164b7a29217SLuis Henriques  * realm, it will execute quota check operation defined by the 'op' parameter.
165b7a29217SLuis Henriques  * The snaprealm walk is interrupted if the quota check detects that the quota
166b7a29217SLuis Henriques  * is exceeded or if the root inode is reached.
167b7a29217SLuis Henriques  */
168b7a29217SLuis Henriques static bool check_quota_exceeded(struct inode *inode, enum quota_check_op op,
169b7a29217SLuis Henriques 				 loff_t delta)
170b7a29217SLuis Henriques {
171b7a29217SLuis Henriques 	struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
172b7a29217SLuis Henriques 	struct ceph_inode_info *ci;
173b7a29217SLuis Henriques 	struct ceph_snap_realm *realm, *next;
174b7a29217SLuis Henriques 	struct inode *in;
175b7a29217SLuis Henriques 	u64 max, rvalue;
176b7a29217SLuis Henriques 	bool exceeded = false;
177b7a29217SLuis Henriques 
17825963669SYan, Zheng 	if (ceph_snap(inode) != CEPH_NOSNAP)
17925963669SYan, Zheng 		return false;
18025963669SYan, Zheng 
181b7a29217SLuis Henriques 	down_read(&mdsc->snap_rwsem);
182b7a29217SLuis Henriques 	realm = ceph_inode(inode)->i_snap_realm;
18325963669SYan, Zheng 	if (realm)
184b7a29217SLuis Henriques 		ceph_get_snap_realm(mdsc, realm);
18525963669SYan, Zheng 	else
18625963669SYan, Zheng 		pr_err_ratelimited("check_quota_exceeded: ino (%llx.%llx) "
18725963669SYan, Zheng 				   "null i_snap_realm\n", ceph_vinop(inode));
188b7a29217SLuis Henriques 	while (realm) {
189e3161f17SLuis Henriques 		spin_lock(&realm->inodes_with_caps_lock);
190e3161f17SLuis Henriques 		in = realm->inode ? igrab(realm->inode) : NULL;
191e3161f17SLuis Henriques 		spin_unlock(&realm->inodes_with_caps_lock);
192e3161f17SLuis Henriques 		if (!in)
193b7a29217SLuis Henriques 			break;
194e3161f17SLuis Henriques 
195b7a29217SLuis Henriques 		ci = ceph_inode(in);
196b7a29217SLuis Henriques 		spin_lock(&ci->i_ceph_lock);
197b7a29217SLuis Henriques 		if (op == QUOTA_CHECK_MAX_FILES_OP) {
198b7a29217SLuis Henriques 			max = ci->i_max_files;
199b7a29217SLuis Henriques 			rvalue = ci->i_rfiles + ci->i_rsubdirs;
2002b83845fSLuis Henriques 		} else {
2012b83845fSLuis Henriques 			max = ci->i_max_bytes;
2022b83845fSLuis Henriques 			rvalue = ci->i_rbytes;
203b7a29217SLuis Henriques 		}
204b7a29217SLuis Henriques 		spin_unlock(&ci->i_ceph_lock);
205b7a29217SLuis Henriques 		switch (op) {
206b7a29217SLuis Henriques 		case QUOTA_CHECK_MAX_FILES_OP:
207b7a29217SLuis Henriques 			exceeded = (max && (rvalue >= max));
208b7a29217SLuis Henriques 			break;
2092b83845fSLuis Henriques 		case QUOTA_CHECK_MAX_BYTES_OP:
2102b83845fSLuis Henriques 			exceeded = (max && (rvalue + delta > max));
2112b83845fSLuis Henriques 			break;
2121ab302a0SLuis Henriques 		case QUOTA_CHECK_MAX_BYTES_APPROACHING_OP:
2131ab302a0SLuis Henriques 			if (max) {
2141ab302a0SLuis Henriques 				if (rvalue >= max)
2151ab302a0SLuis Henriques 					exceeded = true;
2161ab302a0SLuis Henriques 				else {
2171ab302a0SLuis Henriques 					/*
2181ab302a0SLuis Henriques 					 * when we're writing more that 1/16th
2191ab302a0SLuis Henriques 					 * of the available space
2201ab302a0SLuis Henriques 					 */
2211ab302a0SLuis Henriques 					exceeded =
2221ab302a0SLuis Henriques 						(((max - rvalue) >> 4) < delta);
2231ab302a0SLuis Henriques 				}
2241ab302a0SLuis Henriques 			}
2251ab302a0SLuis Henriques 			break;
226b7a29217SLuis Henriques 		default:
227b7a29217SLuis Henriques 			/* Shouldn't happen */
228b7a29217SLuis Henriques 			pr_warn("Invalid quota check op (%d)\n", op);
229b7a29217SLuis Henriques 			exceeded = true; /* Just break the loop */
230b7a29217SLuis Henriques 		}
231b7a29217SLuis Henriques 		iput(in);
232b7a29217SLuis Henriques 
233b7a29217SLuis Henriques 		next = realm->parent;
2340eb6bbe4SYan, Zheng 		if (exceeded || !next)
2350eb6bbe4SYan, Zheng 			break;
236b7a29217SLuis Henriques 		ceph_get_snap_realm(mdsc, next);
237b7a29217SLuis Henriques 		ceph_put_snap_realm(mdsc, realm);
238b7a29217SLuis Henriques 		realm = next;
239b7a29217SLuis Henriques 	}
24071f2cc64SLuis Henriques 	if (realm)
241b7a29217SLuis Henriques 		ceph_put_snap_realm(mdsc, realm);
242b7a29217SLuis Henriques 	up_read(&mdsc->snap_rwsem);
243b7a29217SLuis Henriques 
244b7a29217SLuis Henriques 	return exceeded;
245b7a29217SLuis Henriques }
246b7a29217SLuis Henriques 
247b7a29217SLuis Henriques /*
248b7a29217SLuis Henriques  * ceph_quota_is_max_files_exceeded - check if we can create a new file
249b7a29217SLuis Henriques  * @inode:	directory where a new file is being created
250b7a29217SLuis Henriques  *
251b7a29217SLuis Henriques  * This functions returns true is max_files quota allows a new file to be
252b7a29217SLuis Henriques  * created.  It is necessary to walk through the snaprealm hierarchy (until the
253b7a29217SLuis Henriques  * FS root) to check all realms with quotas set.
254b7a29217SLuis Henriques  */
255b7a29217SLuis Henriques bool ceph_quota_is_max_files_exceeded(struct inode *inode)
256b7a29217SLuis Henriques {
257d557c48dSLuis Henriques 	if (!ceph_has_realms_with_quotas(inode))
258d557c48dSLuis Henriques 		return false;
259d557c48dSLuis Henriques 
260b7a29217SLuis Henriques 	WARN_ON(!S_ISDIR(inode->i_mode));
261b7a29217SLuis Henriques 
262b7a29217SLuis Henriques 	return check_quota_exceeded(inode, QUOTA_CHECK_MAX_FILES_OP, 0);
263b7a29217SLuis Henriques }
2642b83845fSLuis Henriques 
2652b83845fSLuis Henriques /*
2662b83845fSLuis Henriques  * ceph_quota_is_max_bytes_exceeded - check if we can write to a file
2672b83845fSLuis Henriques  * @inode:	inode being written
2682b83845fSLuis Henriques  * @newsize:	new size if write succeeds
2692b83845fSLuis Henriques  *
2702b83845fSLuis Henriques  * This functions returns true is max_bytes quota allows a file size to reach
2712b83845fSLuis Henriques  * @newsize; it returns false otherwise.
2722b83845fSLuis Henriques  */
2732b83845fSLuis Henriques bool ceph_quota_is_max_bytes_exceeded(struct inode *inode, loff_t newsize)
2742b83845fSLuis Henriques {
2752b83845fSLuis Henriques 	loff_t size = i_size_read(inode);
2762b83845fSLuis Henriques 
277d557c48dSLuis Henriques 	if (!ceph_has_realms_with_quotas(inode))
278d557c48dSLuis Henriques 		return false;
279d557c48dSLuis Henriques 
2802b83845fSLuis Henriques 	/* return immediately if we're decreasing file size */
2812b83845fSLuis Henriques 	if (newsize <= size)
2822b83845fSLuis Henriques 		return false;
2832b83845fSLuis Henriques 
2842b83845fSLuis Henriques 	return check_quota_exceeded(inode, QUOTA_CHECK_MAX_BYTES_OP, (newsize - size));
2852b83845fSLuis Henriques }
2861ab302a0SLuis Henriques 
2871ab302a0SLuis Henriques /*
2881ab302a0SLuis Henriques  * ceph_quota_is_max_bytes_approaching - check if we're reaching max_bytes
2891ab302a0SLuis Henriques  * @inode:	inode being written
2901ab302a0SLuis Henriques  * @newsize:	new size if write succeeds
2911ab302a0SLuis Henriques  *
2921ab302a0SLuis Henriques  * This function returns true if the new file size @newsize will be consuming
2931ab302a0SLuis Henriques  * more than 1/16th of the available quota space; it returns false otherwise.
2941ab302a0SLuis Henriques  */
2951ab302a0SLuis Henriques bool ceph_quota_is_max_bytes_approaching(struct inode *inode, loff_t newsize)
2961ab302a0SLuis Henriques {
2971ab302a0SLuis Henriques 	loff_t size = ceph_inode(inode)->i_reported_size;
2981ab302a0SLuis Henriques 
299d557c48dSLuis Henriques 	if (!ceph_has_realms_with_quotas(inode))
300d557c48dSLuis Henriques 		return false;
301d557c48dSLuis Henriques 
3021ab302a0SLuis Henriques 	/* return immediately if we're decreasing file size */
3031ab302a0SLuis Henriques 	if (newsize <= size)
3041ab302a0SLuis Henriques 		return false;
3051ab302a0SLuis Henriques 
3061ab302a0SLuis Henriques 	return check_quota_exceeded(inode, QUOTA_CHECK_MAX_BYTES_APPROACHING_OP,
3071ab302a0SLuis Henriques 				    (newsize - size));
3081ab302a0SLuis Henriques }
3099122eed5SLuis Henriques 
3109122eed5SLuis Henriques /*
3119122eed5SLuis Henriques  * ceph_quota_update_statfs - if root has quota update statfs with quota status
3129122eed5SLuis Henriques  * @fsc:	filesystem client instance
3139122eed5SLuis Henriques  * @buf:	statfs to update
3149122eed5SLuis Henriques  *
3159122eed5SLuis Henriques  * If the mounted filesystem root has max_bytes quota set, update the filesystem
3169122eed5SLuis Henriques  * statistics with the quota status.
3179122eed5SLuis Henriques  *
3189122eed5SLuis Henriques  * This function returns true if the stats have been updated, false otherwise.
3199122eed5SLuis Henriques  */
3209122eed5SLuis Henriques bool ceph_quota_update_statfs(struct ceph_fs_client *fsc, struct kstatfs *buf)
3219122eed5SLuis Henriques {
3229122eed5SLuis Henriques 	struct ceph_mds_client *mdsc = fsc->mdsc;
3239122eed5SLuis Henriques 	struct ceph_inode_info *ci;
3249122eed5SLuis Henriques 	struct ceph_snap_realm *realm;
3259122eed5SLuis Henriques 	struct inode *in;
3269122eed5SLuis Henriques 	u64 total = 0, used, free;
3279122eed5SLuis Henriques 	bool is_updated = false;
3289122eed5SLuis Henriques 
3299122eed5SLuis Henriques 	down_read(&mdsc->snap_rwsem);
3309122eed5SLuis Henriques 	realm = get_quota_realm(mdsc, d_inode(fsc->sb->s_root));
3319122eed5SLuis Henriques 	up_read(&mdsc->snap_rwsem);
3329122eed5SLuis Henriques 	if (!realm)
3339122eed5SLuis Henriques 		return false;
3349122eed5SLuis Henriques 
3359122eed5SLuis Henriques 	spin_lock(&realm->inodes_with_caps_lock);
3369122eed5SLuis Henriques 	in = realm->inode ? igrab(realm->inode) : NULL;
3379122eed5SLuis Henriques 	spin_unlock(&realm->inodes_with_caps_lock);
3389122eed5SLuis Henriques 	if (in) {
3399122eed5SLuis Henriques 		ci = ceph_inode(in);
3409122eed5SLuis Henriques 		spin_lock(&ci->i_ceph_lock);
3419122eed5SLuis Henriques 		if (ci->i_max_bytes) {
3429122eed5SLuis Henriques 			total = ci->i_max_bytes >> CEPH_BLOCK_SHIFT;
3439122eed5SLuis Henriques 			used = ci->i_rbytes >> CEPH_BLOCK_SHIFT;
3449122eed5SLuis Henriques 			/* It is possible for a quota to be exceeded.
3459122eed5SLuis Henriques 			 * Report 'zero' in that case
3469122eed5SLuis Henriques 			 */
3479122eed5SLuis Henriques 			free = total > used ? total - used : 0;
3489122eed5SLuis Henriques 		}
3499122eed5SLuis Henriques 		spin_unlock(&ci->i_ceph_lock);
3509122eed5SLuis Henriques 		if (total) {
3519122eed5SLuis Henriques 			buf->f_blocks = total;
3529122eed5SLuis Henriques 			buf->f_bfree = free;
3539122eed5SLuis Henriques 			buf->f_bavail = free;
3549122eed5SLuis Henriques 			is_updated = true;
3559122eed5SLuis Henriques 		}
3569122eed5SLuis Henriques 		iput(in);
3579122eed5SLuis Henriques 	}
3589122eed5SLuis Henriques 	ceph_put_snap_realm(mdsc, realm);
3599122eed5SLuis Henriques 
3609122eed5SLuis Henriques 	return is_updated;
3619122eed5SLuis Henriques }
3629122eed5SLuis Henriques 
363