1 // SPDX-License-Identifier: GPL-2.0
3 * quota.c - CephFS quota
5 * Copyright (C) 2017-2018 SUSE
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "mds_client.h"
24 void ceph_adjust_quota_realms_count(struct inode
*inode
, bool inc
)
26 struct ceph_mds_client
*mdsc
= ceph_inode_to_client(inode
)->mdsc
;
28 atomic64_inc(&mdsc
->quotarealms_count
);
30 atomic64_dec(&mdsc
->quotarealms_count
);
33 static inline bool ceph_has_realms_with_quotas(struct inode
*inode
)
35 struct ceph_mds_client
*mdsc
= ceph_inode_to_client(inode
)->mdsc
;
36 return atomic64_read(&mdsc
->quotarealms_count
) > 0;
39 void ceph_handle_quota(struct ceph_mds_client
*mdsc
,
40 struct ceph_mds_session
*session
,
43 struct super_block
*sb
= mdsc
->fsc
->sb
;
44 struct ceph_mds_quota
*h
= msg
->front
.iov_base
;
45 struct ceph_vino vino
;
47 struct ceph_inode_info
*ci
;
49 if (msg
->front
.iov_len
!= sizeof(*h
)) {
50 pr_err("%s corrupt message mds%d len %d\n", __func__
,
51 session
->s_mds
, (int)msg
->front
.iov_len
);
56 /* increment msg sequence number */
57 mutex_lock(&session
->s_mutex
);
59 mutex_unlock(&session
->s_mutex
);
62 vino
.ino
= le64_to_cpu(h
->ino
);
63 vino
.snap
= CEPH_NOSNAP
;
64 inode
= ceph_find_inode(sb
, vino
);
66 pr_warn("Failed to find inode %llu\n", vino
.ino
);
69 ci
= ceph_inode(inode
);
71 spin_lock(&ci
->i_ceph_lock
);
72 ci
->i_rbytes
= le64_to_cpu(h
->rbytes
);
73 ci
->i_rfiles
= le64_to_cpu(h
->rfiles
);
74 ci
->i_rsubdirs
= le64_to_cpu(h
->rsubdirs
);
75 __ceph_update_quota(ci
, le64_to_cpu(h
->max_bytes
),
76 le64_to_cpu(h
->max_files
));
77 spin_unlock(&ci
->i_ceph_lock
);
83 * This function walks through the snaprealm for an inode and returns the
84 * ceph_snap_realm for the first snaprealm that has quotas set (either max_files
85 * or max_bytes). If the root is reached, return the root ceph_snap_realm
88 * Note that the caller is responsible for calling ceph_put_snap_realm() on the
91 static struct ceph_snap_realm
*get_quota_realm(struct ceph_mds_client
*mdsc
,
94 struct ceph_inode_info
*ci
= NULL
;
95 struct ceph_snap_realm
*realm
, *next
;
96 struct ceph_vino vino
;
100 realm
= ceph_inode(inode
)->i_snap_realm
;
101 ceph_get_snap_realm(mdsc
, realm
);
103 vino
.ino
= realm
->ino
;
104 vino
.snap
= CEPH_NOSNAP
;
105 in
= ceph_find_inode(inode
->i_sb
, vino
);
107 pr_warn("Failed to find inode for %llu\n", vino
.ino
);
111 has_quota
= __ceph_has_any_quota(ci
);
114 next
= realm
->parent
;
115 if (has_quota
|| !next
)
118 ceph_get_snap_realm(mdsc
, next
);
119 ceph_put_snap_realm(mdsc
, realm
);
123 ceph_put_snap_realm(mdsc
, realm
);
128 bool ceph_quota_is_same_realm(struct inode
*old
, struct inode
*new)
130 struct ceph_mds_client
*mdsc
= ceph_inode_to_client(old
)->mdsc
;
131 struct ceph_snap_realm
*old_realm
, *new_realm
;
134 down_read(&mdsc
->snap_rwsem
);
135 old_realm
= get_quota_realm(mdsc
, old
);
136 new_realm
= get_quota_realm(mdsc
, new);
137 is_same
= (old_realm
== new_realm
);
138 up_read(&mdsc
->snap_rwsem
);
141 ceph_put_snap_realm(mdsc
, old_realm
);
143 ceph_put_snap_realm(mdsc
, new_realm
);
148 enum quota_check_op
{
149 QUOTA_CHECK_MAX_FILES_OP
, /* check quota max_files limit */
150 QUOTA_CHECK_MAX_BYTES_OP
, /* check quota max_files limit */
151 QUOTA_CHECK_MAX_BYTES_APPROACHING_OP
/* check if quota max_files
152 limit is approaching */
156 * check_quota_exceeded() will walk up the snaprealm hierarchy and, for each
157 * realm, it will execute quota check operation defined by the 'op' parameter.
158 * The snaprealm walk is interrupted if the quota check detects that the quota
159 * is exceeded or if the root inode is reached.
161 static bool check_quota_exceeded(struct inode
*inode
, enum quota_check_op op
,
164 struct ceph_mds_client
*mdsc
= ceph_inode_to_client(inode
)->mdsc
;
165 struct ceph_inode_info
*ci
;
166 struct ceph_snap_realm
*realm
, *next
;
167 struct ceph_vino vino
;
170 bool exceeded
= false;
172 down_read(&mdsc
->snap_rwsem
);
173 realm
= ceph_inode(inode
)->i_snap_realm
;
174 ceph_get_snap_realm(mdsc
, realm
);
176 vino
.ino
= realm
->ino
;
177 vino
.snap
= CEPH_NOSNAP
;
178 in
= ceph_find_inode(inode
->i_sb
, vino
);
180 pr_warn("Failed to find inode for %llu\n", vino
.ino
);
184 spin_lock(&ci
->i_ceph_lock
);
185 if (op
== QUOTA_CHECK_MAX_FILES_OP
) {
186 max
= ci
->i_max_files
;
187 rvalue
= ci
->i_rfiles
+ ci
->i_rsubdirs
;
189 max
= ci
->i_max_bytes
;
190 rvalue
= ci
->i_rbytes
;
192 spin_unlock(&ci
->i_ceph_lock
);
194 case QUOTA_CHECK_MAX_FILES_OP
:
195 exceeded
= (max
&& (rvalue
>= max
));
197 case QUOTA_CHECK_MAX_BYTES_OP
:
198 exceeded
= (max
&& (rvalue
+ delta
> max
));
200 case QUOTA_CHECK_MAX_BYTES_APPROACHING_OP
:
206 * when we're writing more that 1/16th
207 * of the available space
210 (((max
- rvalue
) >> 4) < delta
);
215 /* Shouldn't happen */
216 pr_warn("Invalid quota check op (%d)\n", op
);
217 exceeded
= true; /* Just break the loop */
221 next
= realm
->parent
;
222 if (exceeded
|| !next
)
224 ceph_get_snap_realm(mdsc
, next
);
225 ceph_put_snap_realm(mdsc
, realm
);
228 ceph_put_snap_realm(mdsc
, realm
);
229 up_read(&mdsc
->snap_rwsem
);
235 * ceph_quota_is_max_files_exceeded - check if we can create a new file
236 * @inode: directory where a new file is being created
238 * This functions returns true is max_files quota allows a new file to be
239 * created. It is necessary to walk through the snaprealm hierarchy (until the
240 * FS root) to check all realms with quotas set.
242 bool ceph_quota_is_max_files_exceeded(struct inode
*inode
)
244 if (!ceph_has_realms_with_quotas(inode
))
247 WARN_ON(!S_ISDIR(inode
->i_mode
));
249 return check_quota_exceeded(inode
, QUOTA_CHECK_MAX_FILES_OP
, 0);
253 * ceph_quota_is_max_bytes_exceeded - check if we can write to a file
254 * @inode: inode being written
255 * @newsize: new size if write succeeds
257 * This functions returns true is max_bytes quota allows a file size to reach
258 * @newsize; it returns false otherwise.
260 bool ceph_quota_is_max_bytes_exceeded(struct inode
*inode
, loff_t newsize
)
262 loff_t size
= i_size_read(inode
);
264 if (!ceph_has_realms_with_quotas(inode
))
267 /* return immediately if we're decreasing file size */
271 return check_quota_exceeded(inode
, QUOTA_CHECK_MAX_BYTES_OP
, (newsize
- size
));
275 * ceph_quota_is_max_bytes_approaching - check if we're reaching max_bytes
276 * @inode: inode being written
277 * @newsize: new size if write succeeds
279 * This function returns true if the new file size @newsize will be consuming
280 * more than 1/16th of the available quota space; it returns false otherwise.
282 bool ceph_quota_is_max_bytes_approaching(struct inode
*inode
, loff_t newsize
)
284 loff_t size
= ceph_inode(inode
)->i_reported_size
;
286 if (!ceph_has_realms_with_quotas(inode
))
289 /* return immediately if we're decreasing file size */
293 return check_quota_exceeded(inode
, QUOTA_CHECK_MAX_BYTES_APPROACHING_OP
,