Whamcloud - gitweb
LU-5324 lfsck: invalidly memory access in lfsck_del_target
[fs/lustre-release.git] / lustre / osd-zfs / osd_quota.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 021110-1307, USA
20  *
21  * GPL HEADER END
22  */
23 /*
24  * Copyright (c) 2012, Intel Corporation.
25  * Use is subject to license terms.
26  *
27  * Author: Johann Lombardi <johann@whamcloud.com>
28  */
29
30 #include <lustre_quota.h>
31 #include <obd.h>
32 #include "osd_internal.h"
33
34 /**
35  * Helper function to retrieve DMU object id from fid for accounting object
36  */
37 uint64_t osd_quota_fid2dmu(const struct lu_fid *fid)
38 {
39         LASSERT(fid_is_acct(fid));
40         if (fid_oid(fid) == ACCT_GROUP_OID)
41                 return DMU_GROUPUSED_OBJECT;
42         return DMU_USERUSED_OBJECT;
43 }
44
45 /**
46  * Space Accounting Management
47  */
48
49 /**
50  * Return space usage consumed by a given uid or gid.
51  * Block usage is accurrate since it is maintained by DMU itself.
52  * However, DMU does not provide inode accounting, so the #inodes in use
53  * is estimated from the block usage and statfs information.
54  *
55  * \param env   - is the environment passed by the caller
56  * \param dtobj - is the accounting object
57  * \param dtrec - is the record to fill with space usage information
58  * \param dtkey - is the id the of the user or group for which we would
59  *                like to access disk usage.
60  * \param capa - is the capability, not used.
61  *
62  * \retval +ve - success : exact match
63  * \retval -ve - failure
64  */
65 static int osd_acct_index_lookup(const struct lu_env *env,
66                                 struct dt_object *dtobj,
67                                 struct dt_rec *dtrec,
68                                 const struct dt_key *dtkey,
69                                 struct lustre_capa *capa)
70 {
71         struct osd_thread_info  *info = osd_oti_get(env);
72         char                    *buf  = info->oti_buf;
73         struct lquota_acct_rec  *rec  = (struct lquota_acct_rec *)dtrec;
74         struct osd_object       *obj = osd_dt_obj(dtobj);
75         struct osd_device       *osd = osd_obj2dev(obj);
76         int                      rc;
77         uint64_t                 oid;
78         ENTRY;
79
80         rec->bspace = rec->ispace = 0;
81
82         /* convert the 64-bit uid/gid into a string */
83         sprintf(buf, "%llx", *((__u64 *)dtkey));
84         /* fetch DMU object ID (DMU_USERUSED_OBJECT/DMU_GROUPUSED_OBJECT) to be
85          * used */
86         oid = osd_quota_fid2dmu(lu_object_fid(&dtobj->do_lu));
87
88         /* disk usage (in bytes) is maintained by DMU.
89          * DMU_USERUSED_OBJECT/DMU_GROUPUSED_OBJECT are special objects which
90          * not associated with any dmu_but_t (see dnode_special_open()).
91          * As a consequence, we cannot use udmu_zap_lookup() here since it
92          * requires a valid oo_db. */
93         rc = -zap_lookup(osd->od_objset.os, oid, buf, sizeof(uint64_t), 1,
94                         &rec->bspace);
95         if (rc == -ENOENT)
96                 /* user/group has not created anything yet */
97                 CDEBUG(D_QUOTA, "%s: id %s not found in DMU accounting ZAP\n",
98                        osd->od_svname, buf);
99         else if (rc)
100                 RETURN(rc);
101
102         if (osd->od_quota_iused_est) {
103                 if (rec->bspace != 0)
104                         /* estimate #inodes in use */
105                         rec->ispace = udmu_objset_user_iused(&osd->od_objset,
106                                                              rec->bspace);
107                 RETURN(+1);
108         }
109
110         /* as for inode accounting, it is not maintained by DMU, so we just
111          * use our own ZAP to track inode usage */
112         rc = -zap_lookup(osd->od_objset.os, obj->oo_db->db_object,
113                          buf, sizeof(uint64_t), 1, &rec->ispace);
114         if (rc == -ENOENT)
115                 /* user/group has not created any file yet */
116                 CDEBUG(D_QUOTA, "%s: id %s not found in accounting ZAP\n",
117                        osd->od_svname, buf);
118         else if (rc)
119                 RETURN(rc);
120
121         RETURN(+1);
122 }
123
124 /**
125  * Initialize osd Iterator for given osd index object.
126  *
127  * \param  dt    - osd index object
128  * \param  attr  - not used
129  * \param  capa  - BYPASS_CAPA
130  */
131 static struct dt_it *osd_it_acct_init(const struct lu_env *env,
132                                       struct dt_object *dt,
133                                       __u32 attr,
134                                       struct lustre_capa *capa)
135 {
136         struct osd_thread_info  *info = osd_oti_get(env);
137         struct osd_it_quota     *it;
138         struct lu_object        *lo   = &dt->do_lu;
139         struct osd_device       *osd  = osd_dev(lo->lo_dev);
140         int                      rc;
141         ENTRY;
142
143         LASSERT(lu_object_exists(lo));
144
145         if (info == NULL)
146                 RETURN(ERR_PTR(-ENOMEM));
147
148         it = &info->oti_it_quota;
149         memset(it, 0, sizeof(*it));
150         it->oiq_oid = osd_quota_fid2dmu(lu_object_fid(lo));
151
152         /* initialize zap cursor */
153         rc = -udmu_zap_cursor_init(&it->oiq_zc, &osd->od_objset, it->oiq_oid,0);
154         if (rc)
155                 RETURN(ERR_PTR(rc));
156
157         /* take object reference */
158         lu_object_get(lo);
159         it->oiq_obj   = osd_dt_obj(dt);
160         it->oiq_reset = 1;
161
162         RETURN((struct dt_it *)it);
163 }
164
165 /**
166  * Free given iterator.
167  *
168  * \param  di   - osd iterator
169  */
170 static void osd_it_acct_fini(const struct lu_env *env, struct dt_it *di)
171 {
172         struct osd_it_quota *it = (struct osd_it_quota *)di;
173         ENTRY;
174         udmu_zap_cursor_fini(it->oiq_zc);
175         lu_object_put(env, &it->oiq_obj->oo_dt.do_lu);
176         EXIT;
177 }
178
179 /**
180  * Move on to the next valid entry.
181  *
182  * \param  di   - osd iterator
183  *
184  * \retval +ve  - iterator reached the end
185  * \retval   0  - iterator has not reached the end yet
186  * \retval -ve  - unexpected failure
187  */
188 static int osd_it_acct_next(const struct lu_env *env, struct dt_it *di)
189 {
190         struct osd_it_quota     *it = (struct osd_it_quota *)di;
191         int                      rc;
192         ENTRY;
193
194         if (it->oiq_reset == 0)
195                 zap_cursor_advance(it->oiq_zc);
196         it->oiq_reset = 0;
197         rc = -udmu_zap_cursor_retrieve_key(env, it->oiq_zc, NULL, 32);
198         if (rc == -ENOENT) /* reached the end */
199                 RETURN(+1);
200         RETURN(rc);
201 }
202
203 /**
204  * Return pointer to the key under iterator.
205  *
206  * \param  di   - osd iterator
207  */
208 static struct dt_key *osd_it_acct_key(const struct lu_env *env,
209                                       const struct dt_it *di)
210 {
211         struct osd_it_quota     *it = (struct osd_it_quota *)di;
212         struct osd_thread_info  *info = osd_oti_get(env);
213         char                    *buf  = info->oti_buf;
214         char                    *p;
215         int                      rc;
216         ENTRY;
217
218         it->oiq_reset = 0;
219         rc = -udmu_zap_cursor_retrieve_key(env, it->oiq_zc, buf, 32);
220         if (rc)
221                 RETURN(ERR_PTR(rc));
222         it->oiq_id = simple_strtoull(buf, &p, 16);
223         RETURN((struct dt_key *) &it->oiq_id);
224 }
225
226 /**
227  * Return size of key under iterator (in bytes)
228  *
229  * \param  di   - osd iterator
230  */
231 static int osd_it_acct_key_size(const struct lu_env *env,
232                                 const struct dt_it *di)
233 {
234         ENTRY;
235         RETURN((int)sizeof(uint64_t));
236 }
237
238 /**
239  * Return pointer to the record under iterator.
240  *
241  * \param  di    - osd iterator
242  * \param  attr  - not used
243  */
244 static int osd_it_acct_rec(const struct lu_env *env,
245                            const struct dt_it *di,
246                            struct dt_rec *dtrec, __u32 attr)
247 {
248         struct osd_thread_info  *info = osd_oti_get(env);
249         char                    *buf  = info->oti_buf;
250         struct osd_it_quota     *it = (struct osd_it_quota *)di;
251         struct lquota_acct_rec  *rec  = (struct lquota_acct_rec *)dtrec;
252         struct osd_object       *obj = it->oiq_obj;
253         struct osd_device       *osd = osd_obj2dev(obj);
254         int                      bytes_read;
255         int                      rc;
256         ENTRY;
257
258         it->oiq_reset = 0;
259         rec->ispace = rec->bspace = 0;
260
261         /* retrieve block usage from the DMU accounting object */
262         rc = -udmu_zap_cursor_retrieve_value(env, it->oiq_zc,
263                                              (char *)&rec->bspace,
264                                              sizeof(uint64_t), &bytes_read);
265         if (rc)
266                 RETURN(rc);
267
268         if (osd->od_quota_iused_est) {
269                 if (rec->bspace != 0)
270                         /* estimate #inodes in use */
271                         rec->ispace = udmu_objset_user_iused(&osd->od_objset,
272                                                              rec->bspace);
273                 RETURN(0);
274         }
275
276         /* retrieve key associated with the current cursor */
277         rc = -udmu_zap_cursor_retrieve_key(env, it->oiq_zc, buf, 32);
278         if (rc)
279                 RETURN(rc);
280
281         /* inode accounting is not maintained by DMU, so we use our own ZAP to
282          * track inode usage */
283         rc = -zap_lookup(osd->od_objset.os, it->oiq_obj->oo_db->db_object,
284                          buf, sizeof(uint64_t), 1, &rec->ispace);
285         if (rc == -ENOENT)
286                 /* user/group has not created any file yet */
287                 CDEBUG(D_QUOTA, "%s: id %s not found in accounting ZAP\n",
288                        osd->od_svname, buf);
289         else if (rc)
290                 RETURN(rc);
291
292         RETURN(0);
293 }
294
295 /**
296  * Returns cookie for current Iterator position.
297  *
298  * \param  di    - osd iterator
299  */
300 static __u64 osd_it_acct_store(const struct lu_env *env,
301                                const struct dt_it *di)
302 {
303         struct osd_it_quota *it = (struct osd_it_quota *)di;
304         ENTRY;
305         it->oiq_reset = 0;
306         RETURN(udmu_zap_cursor_serialize(it->oiq_zc));
307 }
308
309 /**
310  * Restore iterator from cookie. if the \a hash isn't found,
311  * restore the first valid record.
312  *
313  * \param  di    - osd iterator
314  * \param  hash  - iterator location cookie
315  *
316  * \retval +ve  - di points to exact matched key
317  * \retval  0   - di points to the first valid record
318  * \retval -ve  - failure
319  */
320 static int osd_it_acct_load(const struct lu_env *env,
321                             const struct dt_it *di, __u64 hash)
322 {
323         struct osd_it_quota     *it  = (struct osd_it_quota *)di;
324         struct osd_device       *osd = osd_obj2dev(it->oiq_obj);
325         zap_cursor_t            *zc;
326         int                      rc;
327         ENTRY;
328
329         /* create new cursor pointing to the new hash */
330         rc = -udmu_zap_cursor_init(&zc, &osd->od_objset, it->oiq_oid, hash);
331         if (rc)
332                 RETURN(rc);
333         udmu_zap_cursor_fini(it->oiq_zc);
334         it->oiq_zc = zc;
335         it->oiq_reset = 0;
336
337         rc = -udmu_zap_cursor_retrieve_key(env, it->oiq_zc, NULL, 32);
338         if (rc == 0)
339                 RETURN(+1);
340         else if (rc == -ENOENT)
341                 RETURN(0);
342         RETURN(rc);
343 }
344
345 /**
346  * Move Iterator to record specified by \a key, if the \a key isn't found,
347  * move to the first valid record.
348  *
349  * \param  di   - osd iterator
350  * \param  key  - uid or gid
351  *
352  * \retval +ve  - di points to exact matched key
353  * \retval 0    - di points to the first valid record
354  * \retval -ve  - failure
355  */
356 static int osd_it_acct_get(const struct lu_env *env, struct dt_it *di,
357                 const struct dt_key *key)
358 {
359         ENTRY;
360
361         /* XXX: like osd_zap_it_get(), API is currently broken */
362         LASSERT(*((__u64 *)key) == 0);
363
364         RETURN(osd_it_acct_load(env, di, 0));
365 }
366
367 /**
368  * Release Iterator
369  *
370  * \param  di   - osd iterator
371  */
372 static void osd_it_acct_put(const struct lu_env *env, struct dt_it *di)
373 {
374 }
375
376 /**
377  * Index and Iterator operations for accounting objects
378  */
379 const struct dt_index_operations osd_acct_index_ops = {
380         .dio_lookup = osd_acct_index_lookup,
381         .dio_it     = {
382                 .init           = osd_it_acct_init,
383                 .fini           = osd_it_acct_fini,
384                 .get            = osd_it_acct_get,
385                 .put            = osd_it_acct_put,
386                 .next           = osd_it_acct_next,
387                 .key            = osd_it_acct_key,
388                 .key_size       = osd_it_acct_key_size,
389                 .rec            = osd_it_acct_rec,
390                 .store          = osd_it_acct_store,
391                 .load           = osd_it_acct_load
392         }
393 };
394
395 /**
396  * Quota Enforcement Management
397  */
398
399 /*
400  * Wrapper for qsd_op_begin().
401  *
402  * \param env    - the environment passed by the caller
403  * \param osd    - is the osd_device
404  * \param uid    - user id of the inode
405  * \param gid    - group id of the inode
406  * \param space  - how many blocks/inodes will be consumed/released
407  * \param oh     - osd transaction handle
408  * \param is_blk - block quota or inode quota?
409  * \param flags  - if the operation is write, return no user quota, no
410  *                  group quota, or sync commit flags to the caller
411  * \param force  - set to 1 when changes are performed by root user and thus
412  *                  can't failed with EDQUOT
413  *
414  * \retval 0      - success
415  * \retval -ve    - failure
416  */
417 int osd_declare_quota(const struct lu_env *env, struct osd_device *osd,
418                       qid_t uid, qid_t gid, long long space,
419                       struct osd_thandle *oh, bool is_blk, int *flags,
420                       bool force)
421 {
422         struct osd_thread_info  *info = osd_oti_get(env);
423         struct lquota_id_info   *qi = &info->oti_qi;
424         struct qsd_instance     *qsd = osd->od_quota_slave;
425         int                      rcu, rcg; /* user & group rc */
426         ENTRY;
427
428         if (unlikely(qsd == NULL))
429                 /* quota slave instance hasn't been allocated yet */
430                 RETURN(0);
431
432         /* let's start with user quota */
433         qi->lqi_id.qid_uid = uid;
434         qi->lqi_type       = USRQUOTA;
435         qi->lqi_space      = space;
436         qi->lqi_is_blk     = is_blk;
437         rcu = qsd_op_begin(env, qsd, &oh->ot_quota_trans, qi, flags);
438
439         if (force && (rcu == -EDQUOT || rcu == -EINPROGRESS))
440                 /* ignore EDQUOT & EINPROGRESS when changes are done by root */
441                 rcu = 0;
442
443         /* For non-fatal error, we want to continue to get the noquota flags
444          * for group id. This is only for commit write, which has @flags passed
445          * in. See osd_declare_write_commit().
446          * When force is set to true, we also want to proceed with the gid */
447         if (rcu && (rcu != -EDQUOT || flags == NULL))
448                 RETURN(rcu);
449
450         /* and now group quota */
451         qi->lqi_id.qid_gid = gid;
452         qi->lqi_type       = GRPQUOTA;
453         rcg = qsd_op_begin(env, qsd, &oh->ot_quota_trans, qi, flags);
454
455         if (force && (rcg == -EDQUOT || rcg == -EINPROGRESS))
456                 /* as before, ignore EDQUOT & EINPROGRESS for root */
457                 rcg = 0;
458
459         RETURN(rcu ? rcu : rcg);
460 }