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