ceph: quota: cleanup license mess
[sfrench/cifs-2.6.git] / fs / ceph / quota.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * quota.c - CephFS quota
4  *
5  * Copyright (C) 2017-2018 SUSE
6  */
7
8 #include <linux/statfs.h>
9
10 #include "super.h"
11 #include "mds_client.h"
12
13 void ceph_adjust_quota_realms_count(struct inode *inode, bool inc)
14 {
15         struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
16         if (inc)
17                 atomic64_inc(&mdsc->quotarealms_count);
18         else
19                 atomic64_dec(&mdsc->quotarealms_count);
20 }
21
22 static inline bool ceph_has_realms_with_quotas(struct inode *inode)
23 {
24         struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
25         return atomic64_read(&mdsc->quotarealms_count) > 0;
26 }
27
28 void ceph_handle_quota(struct ceph_mds_client *mdsc,
29                        struct ceph_mds_session *session,
30                        struct ceph_msg *msg)
31 {
32         struct super_block *sb = mdsc->fsc->sb;
33         struct ceph_mds_quota *h = msg->front.iov_base;
34         struct ceph_vino vino;
35         struct inode *inode;
36         struct ceph_inode_info *ci;
37
38         if (msg->front.iov_len < sizeof(*h)) {
39                 pr_err("%s corrupt message mds%d len %d\n", __func__,
40                        session->s_mds, (int)msg->front.iov_len);
41                 ceph_msg_dump(msg);
42                 return;
43         }
44
45         /* increment msg sequence number */
46         mutex_lock(&session->s_mutex);
47         session->s_seq++;
48         mutex_unlock(&session->s_mutex);
49
50         /* lookup inode */
51         vino.ino = le64_to_cpu(h->ino);
52         vino.snap = CEPH_NOSNAP;
53         inode = ceph_find_inode(sb, vino);
54         if (!inode) {
55                 pr_warn("Failed to find inode %llu\n", vino.ino);
56                 return;
57         }
58         ci = ceph_inode(inode);
59
60         spin_lock(&ci->i_ceph_lock);
61         ci->i_rbytes = le64_to_cpu(h->rbytes);
62         ci->i_rfiles = le64_to_cpu(h->rfiles);
63         ci->i_rsubdirs = le64_to_cpu(h->rsubdirs);
64         __ceph_update_quota(ci, le64_to_cpu(h->max_bytes),
65                             le64_to_cpu(h->max_files));
66         spin_unlock(&ci->i_ceph_lock);
67
68         iput(inode);
69 }
70
71 /*
72  * This function walks through the snaprealm for an inode and returns the
73  * ceph_snap_realm for the first snaprealm that has quotas set (either max_files
74  * or max_bytes).  If the root is reached, return the root ceph_snap_realm
75  * instead.
76  *
77  * Note that the caller is responsible for calling ceph_put_snap_realm() on the
78  * returned realm.
79  */
80 static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc,
81                                                struct inode *inode)
82 {
83         struct ceph_inode_info *ci = NULL;
84         struct ceph_snap_realm *realm, *next;
85         struct inode *in;
86         bool has_quota;
87
88         if (ceph_snap(inode) != CEPH_NOSNAP)
89                 return NULL;
90
91         realm = ceph_inode(inode)->i_snap_realm;
92         if (realm)
93                 ceph_get_snap_realm(mdsc, realm);
94         else
95                 pr_err_ratelimited("get_quota_realm: ino (%llx.%llx) "
96                                    "null i_snap_realm\n", ceph_vinop(inode));
97         while (realm) {
98                 spin_lock(&realm->inodes_with_caps_lock);
99                 in = realm->inode ? igrab(realm->inode) : NULL;
100                 spin_unlock(&realm->inodes_with_caps_lock);
101                 if (!in)
102                         break;
103
104                 ci = ceph_inode(in);
105                 has_quota = __ceph_has_any_quota(ci);
106                 iput(in);
107
108                 next = realm->parent;
109                 if (has_quota || !next)
110                        return realm;
111
112                 ceph_get_snap_realm(mdsc, next);
113                 ceph_put_snap_realm(mdsc, realm);
114                 realm = next;
115         }
116         if (realm)
117                 ceph_put_snap_realm(mdsc, realm);
118
119         return NULL;
120 }
121
122 bool ceph_quota_is_same_realm(struct inode *old, struct inode *new)
123 {
124         struct ceph_mds_client *mdsc = ceph_inode_to_client(old)->mdsc;
125         struct ceph_snap_realm *old_realm, *new_realm;
126         bool is_same;
127
128         down_read(&mdsc->snap_rwsem);
129         old_realm = get_quota_realm(mdsc, old);
130         new_realm = get_quota_realm(mdsc, new);
131         is_same = (old_realm == new_realm);
132         up_read(&mdsc->snap_rwsem);
133
134         if (old_realm)
135                 ceph_put_snap_realm(mdsc, old_realm);
136         if (new_realm)
137                 ceph_put_snap_realm(mdsc, new_realm);
138
139         return is_same;
140 }
141
142 enum quota_check_op {
143         QUOTA_CHECK_MAX_FILES_OP,       /* check quota max_files limit */
144         QUOTA_CHECK_MAX_BYTES_OP,       /* check quota max_files limit */
145         QUOTA_CHECK_MAX_BYTES_APPROACHING_OP    /* check if quota max_files
146                                                    limit is approaching */
147 };
148
149 /*
150  * check_quota_exceeded() will walk up the snaprealm hierarchy and, for each
151  * realm, it will execute quota check operation defined by the 'op' parameter.
152  * The snaprealm walk is interrupted if the quota check detects that the quota
153  * is exceeded or if the root inode is reached.
154  */
155 static bool check_quota_exceeded(struct inode *inode, enum quota_check_op op,
156                                  loff_t delta)
157 {
158         struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
159         struct ceph_inode_info *ci;
160         struct ceph_snap_realm *realm, *next;
161         struct inode *in;
162         u64 max, rvalue;
163         bool exceeded = false;
164
165         if (ceph_snap(inode) != CEPH_NOSNAP)
166                 return false;
167
168         down_read(&mdsc->snap_rwsem);
169         realm = ceph_inode(inode)->i_snap_realm;
170         if (realm)
171                 ceph_get_snap_realm(mdsc, realm);
172         else
173                 pr_err_ratelimited("check_quota_exceeded: ino (%llx.%llx) "
174                                    "null i_snap_realm\n", ceph_vinop(inode));
175         while (realm) {
176                 spin_lock(&realm->inodes_with_caps_lock);
177                 in = realm->inode ? igrab(realm->inode) : NULL;
178                 spin_unlock(&realm->inodes_with_caps_lock);
179                 if (!in)
180                         break;
181
182                 ci = ceph_inode(in);
183                 spin_lock(&ci->i_ceph_lock);
184                 if (op == QUOTA_CHECK_MAX_FILES_OP) {
185                         max = ci->i_max_files;
186                         rvalue = ci->i_rfiles + ci->i_rsubdirs;
187                 } else {
188                         max = ci->i_max_bytes;
189                         rvalue = ci->i_rbytes;
190                 }
191                 spin_unlock(&ci->i_ceph_lock);
192                 switch (op) {
193                 case QUOTA_CHECK_MAX_FILES_OP:
194                         exceeded = (max && (rvalue >= max));
195                         break;
196                 case QUOTA_CHECK_MAX_BYTES_OP:
197                         exceeded = (max && (rvalue + delta > max));
198                         break;
199                 case QUOTA_CHECK_MAX_BYTES_APPROACHING_OP:
200                         if (max) {
201                                 if (rvalue >= max)
202                                         exceeded = true;
203                                 else {
204                                         /*
205                                          * when we're writing more that 1/16th
206                                          * of the available space
207                                          */
208                                         exceeded =
209                                                 (((max - rvalue) >> 4) < delta);
210                                 }
211                         }
212                         break;
213                 default:
214                         /* Shouldn't happen */
215                         pr_warn("Invalid quota check op (%d)\n", op);
216                         exceeded = true; /* Just break the loop */
217                 }
218                 iput(in);
219
220                 next = realm->parent;
221                 if (exceeded || !next)
222                         break;
223                 ceph_get_snap_realm(mdsc, next);
224                 ceph_put_snap_realm(mdsc, realm);
225                 realm = next;
226         }
227         if (realm)
228                 ceph_put_snap_realm(mdsc, realm);
229         up_read(&mdsc->snap_rwsem);
230
231         return exceeded;
232 }
233
234 /*
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
237  *
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.
241  */
242 bool ceph_quota_is_max_files_exceeded(struct inode *inode)
243 {
244         if (!ceph_has_realms_with_quotas(inode))
245                 return false;
246
247         WARN_ON(!S_ISDIR(inode->i_mode));
248
249         return check_quota_exceeded(inode, QUOTA_CHECK_MAX_FILES_OP, 0);
250 }
251
252 /*
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
256  *
257  * This functions returns true is max_bytes quota allows a file size to reach
258  * @newsize; it returns false otherwise.
259  */
260 bool ceph_quota_is_max_bytes_exceeded(struct inode *inode, loff_t newsize)
261 {
262         loff_t size = i_size_read(inode);
263
264         if (!ceph_has_realms_with_quotas(inode))
265                 return false;
266
267         /* return immediately if we're decreasing file size */
268         if (newsize <= size)
269                 return false;
270
271         return check_quota_exceeded(inode, QUOTA_CHECK_MAX_BYTES_OP, (newsize - size));
272 }
273
274 /*
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
278  *
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.
281  */
282 bool ceph_quota_is_max_bytes_approaching(struct inode *inode, loff_t newsize)
283 {
284         loff_t size = ceph_inode(inode)->i_reported_size;
285
286         if (!ceph_has_realms_with_quotas(inode))
287                 return false;
288
289         /* return immediately if we're decreasing file size */
290         if (newsize <= size)
291                 return false;
292
293         return check_quota_exceeded(inode, QUOTA_CHECK_MAX_BYTES_APPROACHING_OP,
294                                     (newsize - size));
295 }
296
297 /*
298  * ceph_quota_update_statfs - if root has quota update statfs with quota status
299  * @fsc:        filesystem client instance
300  * @buf:        statfs to update
301  *
302  * If the mounted filesystem root has max_bytes quota set, update the filesystem
303  * statistics with the quota status.
304  *
305  * This function returns true if the stats have been updated, false otherwise.
306  */
307 bool ceph_quota_update_statfs(struct ceph_fs_client *fsc, struct kstatfs *buf)
308 {
309         struct ceph_mds_client *mdsc = fsc->mdsc;
310         struct ceph_inode_info *ci;
311         struct ceph_snap_realm *realm;
312         struct inode *in;
313         u64 total = 0, used, free;
314         bool is_updated = false;
315
316         down_read(&mdsc->snap_rwsem);
317         realm = get_quota_realm(mdsc, d_inode(fsc->sb->s_root));
318         up_read(&mdsc->snap_rwsem);
319         if (!realm)
320                 return false;
321
322         spin_lock(&realm->inodes_with_caps_lock);
323         in = realm->inode ? igrab(realm->inode) : NULL;
324         spin_unlock(&realm->inodes_with_caps_lock);
325         if (in) {
326                 ci = ceph_inode(in);
327                 spin_lock(&ci->i_ceph_lock);
328                 if (ci->i_max_bytes) {
329                         total = ci->i_max_bytes >> CEPH_BLOCK_SHIFT;
330                         used = ci->i_rbytes >> CEPH_BLOCK_SHIFT;
331                         /* It is possible for a quota to be exceeded.
332                          * Report 'zero' in that case
333                          */
334                         free = total > used ? total - used : 0;
335                 }
336                 spin_unlock(&ci->i_ceph_lock);
337                 if (total) {
338                         buf->f_blocks = total;
339                         buf->f_bfree = free;
340                         buf->f_bavail = free;
341                         is_updated = true;
342                 }
343                 iput(in);
344         }
345         ceph_put_snap_realm(mdsc, realm);
346
347         return is_updated;
348 }
349