1 // SPDX-License-Identifier: GPL-2.0
4 * Copyright (c) 2012, 2017, Intel Corporation.
5 * Use is subject to license terms.
9 * The disk API is used by both the QMT and QSD to access/update on-disk index
10 * files. The API consists of the following functions:
12 * - lquota_disk_dir_find_create: look-up quota directory, create it if not
14 * - lquota_disk_glb_find_create: look-up global index file, create it if not
16 * - lquota_disk_slv_find: look-up a slave index file.
17 * - lquota_disk_slv_find_create: look-up a slave index file. Allocate a FID if
18 * required and create the index file on disk if
20 * - lquota_disk_for_each_slv: iterate over all existing slave index files
21 * - lquota_disk_read: read quota settings from an index file
22 * - lquota_disk_declare_write: reserve credits to update a record in an index
24 * - lquota_disk_write: update a record in an index file
25 * - lquota_disk_update_ver: update version of an index file
27 * Author: Johann Lombardi <johann.lombardi@intel.com>
28 * Author: Niu Yawei <yawei.niu@intel.com>
31 #define DEBUG_SUBSYSTEM S_LQUOTA
33 #include <obd_class.h>
34 #include "lquota_internal.h"
36 #define LQUOTA_MODE (S_IFREG | S_IRUGO | S_IWUSR)
39 * Helper function looking up & creating if not found an index file with a
42 static struct dt_object *
43 lquota_disk_find_create(const struct lu_env *env, struct dt_device *dev,
44 struct dt_object *parent, struct lu_fid *fid,
45 const struct dt_index_features *idx_feat,
48 struct lquota_thread_info *qti = lquota_info(env);
49 struct dt_object *obj;
50 struct local_oid_storage *los;
54 /* Set up local storage */
55 rc = local_oid_storage_init(env, dev, fid, &los);
59 /* lookup/create slave index file */
60 obj = local_index_find_or_create(env, los, parent, name, LQUOTA_MODE,
65 /* local_oid_storage_fini() will finalize the local storage device,
66 * we have to open the object in another device stack */
67 qti->qti_fid = obj->do_lu.lo_header->loh_fid;
68 dt_object_put_nocache(env, obj);
69 obj = dt_locate(env, dev, &qti->qti_fid);
73 local_oid_storage_fini(env, los);
78 * helper function to generate the filename associated with a slave index file
80 static inline int lquota_disk_slv_filename(const struct lu_fid *glb_fid,
81 struct obd_uuid *uuid,
84 char *name, *uuid_str;
86 /* In most case, the uuid is NULL terminated */
87 if (uuid->uuid[sizeof(*uuid) - 1] != '\0') {
88 OBD_ALLOC(uuid_str, sizeof(*uuid));
91 memcpy(uuid_str, uuid->uuid, sizeof(*uuid) - 1);
93 uuid_str = (char *)uuid->uuid;
96 /* we strip the slave's UUID (in the form of fsname-OST0001_UUID) of
97 * the filesystem name in case this one is changed in the future */
98 name = strrchr(uuid_str, '-');
100 name = strrchr(uuid_str, ':');
102 CERROR("Failed to extract extract filesystem "
103 "name from UUID %s\n", uuid_str);
104 if (uuid_str != uuid->uuid)
105 OBD_FREE(uuid_str, sizeof(*uuid));
111 /* the filename is composed of the most signicant bits of the global
112 * FID, that's to say the oid which encodes the pool type and
113 * quota type, followed by the export UUID */
114 sprintf(filename, "0x%x-%s", glb_fid->f_oid, name);
116 if (uuid_str != uuid->uuid)
117 OBD_FREE(uuid_str, sizeof(*uuid));
123 * Set up quota directory (either "quota_master" or "quota_slave") for a QMT or
124 * QSD instance. This function is also used to create per-pool directory on
126 * The directory is created with a local sequence if it does not exist already.
127 * This function is called at ->ldo_prepare time when the full device stack is
130 * \param env - is the environment passed by the caller
131 * \param dev - is the dt_device where to create the quota directory
132 * \param parent - is the parent directory. If not specified, the directory
133 * will be created under the root directory
134 * \param name - is the name of quota directory to be created
136 * \retval - pointer to quota root dt_object on success, appropriate error
139 struct dt_object *lquota_disk_dir_find_create(const struct lu_env *env,
140 struct dt_device *dev,
141 struct dt_object *parent,
144 struct lquota_thread_info *qti = lquota_info(env);
145 struct dt_object *qt_dir = NULL;
146 struct local_oid_storage *los = NULL;
150 /* Set up local storage to create the quota directory.
151 * We use the sequence reserved for local named objects */
152 lu_local_name_obj_fid(&qti->qti_fid, 1);
153 rc = local_oid_storage_init(env, dev, &qti->qti_fid, &los);
157 if (parent == NULL) {
158 /* Fetch dt object associated with root directory */
159 rc = dt_root_get(env, dev, &qti->qti_fid);
163 parent = dt_locate_at(env, dev, &qti->qti_fid,
164 dev->dd_lu_dev.ld_site->ls_top_dev, NULL);
166 GOTO(out, rc = PTR_ERR(parent));
168 lu_object_get(&parent->do_lu);
171 /* create quota directory to be used for all quota index files */
172 qt_dir = local_file_find_or_create(env, los, parent, name, S_IFDIR |
173 S_IRUGO | S_IWUSR | S_IXUGO);
175 GOTO(out, rc = PTR_ERR(qt_dir));
177 /* local_oid_storage_fini() will finalize the local storage device,
178 * we have to open the object in another device stack */
179 qti->qti_fid = qt_dir->do_lu.lo_header->loh_fid;
180 dt_object_put_nocache(env, qt_dir);
181 qt_dir = dt_locate(env, dev, &qti->qti_fid);
183 GOTO(out, rc = PTR_ERR(qt_dir));
185 if (!dt_try_as_dir(env, qt_dir, true))
186 GOTO(out, rc = -ENOTDIR);
189 if (parent != NULL && !IS_ERR(parent))
190 dt_object_put(env, parent);
192 local_oid_storage_fini(env, los);
194 if (qt_dir != NULL && !IS_ERR(qt_dir))
195 dt_object_put(env, qt_dir);
196 qt_dir = ERR_PTR(rc);
202 * Look-up/create a global index file.
204 * \param env - is the environment passed by the caller
205 * \parap dev - is the dt_device where to lookup/create the global index file
206 * \param parent - is the parent directory where to create the global index if
208 * \param fid - is the fid of the global index to be looked up/created
209 * \parap local - indicates whether the index should be created with a local
210 * generated fid or with \fid
212 * \retval - pointer to the dt_object of the global index on success,
213 * appropriate error on failure
215 struct dt_object *lquota_disk_glb_find_create(const struct lu_env *env,
216 struct dt_device *dev,
217 struct dt_object *parent,
218 struct lu_fid *fid, bool local)
220 struct lquota_thread_info *qti = lquota_info(env);
221 struct dt_object *glb_idx;
222 const struct dt_index_features *idx_feat;
225 CDEBUG(D_QUOTA, "look-up/create %sglobal idx file ("DFID")\n",
226 local ? "local " : "", PFID(fid));
228 idx_feat = &dt_quota_glb_features;
230 /* the filename is composed of the most signicant bits of the FID,
231 * that's to say the oid which encodes the pool type and quota type */
232 sprintf(qti->qti_buf, "0x%x", fid->f_oid);
235 /* We use the sequence reserved for local named objects */
236 lu_local_name_obj_fid(&qti->qti_fid, 1);
237 glb_idx = lquota_disk_find_create(env, dev, parent,
238 &qti->qti_fid, idx_feat,
241 /* look-up/create global index on disk */
242 glb_idx = local_index_find_or_create_with_fid(env, dev, fid,
249 if (IS_ERR(glb_idx)) {
250 CERROR("%s: failed to look-up/create idx file "DFID" rc:%ld "
251 "local:%d\n", dev->dd_lu_dev.ld_obd->obd_name,
252 PFID(fid), PTR_ERR(glb_idx), local);
256 /* install index operation vector */
257 if (glb_idx->do_index_ops == NULL) {
260 rc = glb_idx->do_ops->do_index_try(env, glb_idx, idx_feat);
262 CERROR("%s: failed to setup index operations for "DFID
263 " rc:%d\n", dev->dd_lu_dev.ld_obd->obd_name,
264 PFID(lu_object_fid(&glb_idx->do_lu)), rc);
265 dt_object_put(env, glb_idx);
266 glb_idx = ERR_PTR(rc);
274 * Look-up a slave index file.
276 * \param env - is the environment passed by the caller
277 * \param dev - is the backend dt_device where to look-up/create the slave index
278 * \param parent - is the parent directory where to lookup the slave index
279 * \param glb_fid - is the fid of the global index file associated with this
281 * \param uuid - is the uuid of slave which is (re)connecting to the master
284 * \retval - pointer to the dt_object of the slave index on success,
285 * appropriate error on failure
287 struct dt_object *lquota_disk_slv_find(const struct lu_env *env,
288 struct dt_device *dev,
289 struct dt_object *parent,
290 const struct lu_fid *glb_fid,
291 struct obd_uuid *uuid)
293 struct lquota_thread_info *qti = lquota_info(env);
294 struct dt_object *slv_idx;
298 LASSERT(uuid != NULL);
300 CDEBUG(D_QUOTA, "lookup slave index file for %s\n",
303 /* generate filename associated with the slave */
304 rc = lquota_disk_slv_filename(glb_fid, uuid, qti->qti_buf);
308 /* lookup slave index file */
309 rc = dt_lookup_dir(env, parent, qti->qti_buf, &qti->qti_fid);
313 /* name is found, get the object */
314 slv_idx = dt_locate(env, dev, &qti->qti_fid);
318 if (slv_idx->do_index_ops == NULL) {
319 rc = slv_idx->do_ops->do_index_try(env, slv_idx,
320 &dt_quota_slv_features);
322 CERROR("%s: failed to setup slave index operations for "
323 "%s, rc:%d\n", dev->dd_lu_dev.ld_obd->obd_name,
324 obd_uuid2str(uuid), rc);
325 dt_object_put(env, slv_idx);
326 slv_idx = ERR_PTR(rc);
334 * Look-up a slave index file. If the slave index isn't found:
335 * - if local is set to false, we allocate a FID from FID_SEQ_QUOTA sequence and
337 * - otherwise, we create the index file with a local reserved FID (see
340 * \param env - is the environment passed by the caller
341 * \param dev - is the backend dt_device where to look-up/create the slave index
342 * \param parent - is the parent directory where to create the slave index if
343 * it does not exist already
344 * \param glb_fid - is the fid of the global index file associated with this
346 * \param uuid - is the uuid of slave which is (re)connecting to the master
348 * \param local - indicate whether to use local reserved FID (LQUOTA_USR_OID
349 * & LQUOTA_GRP_OID) for the slave index creation or to
350 * allocate a new fid from sequence FID_SEQ_QUOTA
352 * \retval - pointer to the dt_object of the slave index on success,
353 * appropriate error on failure
355 struct dt_object *lquota_disk_slv_find_create(const struct lu_env *env,
356 struct dt_device *dev,
357 struct dt_object *parent,
358 struct lu_fid *glb_fid,
359 struct obd_uuid *uuid,
362 struct lquota_thread_info *qti = lquota_info(env);
363 struct dt_object *slv_idx;
367 LASSERT(uuid != NULL);
369 CDEBUG(D_QUOTA, "lookup/create slave index file for %s\n",
372 /* generate filename associated with the slave */
373 rc = lquota_disk_slv_filename(glb_fid, uuid, qti->qti_buf);
377 if (lu_device_is_md(dev->dd_lu_dev.ld_site->ls_top_dev))
378 type = LDD_F_SV_TYPE_MDT;
380 type = LDD_F_SV_TYPE_OST;
382 /* Slave indexes uses the FID_SEQ_QUOTA sequence since they can be read
383 * through the network */
384 qti->qti_fid.f_seq = FID_SEQ_QUOTA;
385 qti->qti_fid.f_ver = 0;
387 enum lquota_res_type pool_type;
388 enum lquota_type qtype;
390 rc = lquota_extract_fid(glb_fid, &pool_type, &qtype);
394 /* use predefined fid in the reserved oid list */
395 if ((type == LDD_F_SV_TYPE_MDT && pool_type == LQUOTA_RES_MD) ||
396 (type == LDD_F_SV_TYPE_OST && pool_type == LQUOTA_RES_DT))
397 qti->qti_fid.f_oid = qtype2slv_oid(qtype);
399 qti->qti_fid.f_oid = pool_type << 16 |
400 qtype2slv_oid(qtype);
402 slv_idx = local_index_find_or_create_with_fid(env, dev,
407 &dt_quota_slv_features);
409 /* allocate fid dynamically if index does not exist already */
410 qti->qti_fid.f_oid = LQUOTA_GENERATED_OID;
412 /* lookup/create slave index file */
413 slv_idx = lquota_disk_find_create(env, dev, parent,
415 &dt_quota_slv_features,
422 /* install index operation vector */
423 if (slv_idx->do_index_ops == NULL) {
424 rc = slv_idx->do_ops->do_index_try(env, slv_idx,
425 &dt_quota_slv_features);
427 CERROR("%s: failed to setup index operations for "DFID
428 " rc:%d\n", dev->dd_lu_dev.ld_obd->obd_name,
429 PFID(lu_object_fid(&slv_idx->do_lu)), rc);
430 dt_object_put(env, slv_idx);
431 slv_idx = ERR_PTR(rc);
439 * Iterate over all slave index files associated with global index \glb_fid and
440 * invoke a callback function for each slave index file.
442 * \param env - is the environment passed by the caller
443 * \param parent - is the parent directory where the slave index files are
445 * \param glb_fid - is the fid of the global index file associated with the
446 * slave indexes to scan
447 * \param func - is the callback function to call each time a slave index
449 * \param arg - is an opaq argument passed to the callback function \func
451 int lquota_disk_for_each_slv(const struct lu_env *env, struct dt_object *parent,
452 struct lu_fid *glb_fid, lquota_disk_slv_cb_t func,
455 struct lquota_thread_info *qti = lquota_info(env);
457 const struct dt_it_ops *iops;
462 OBD_ALLOC(name, LQUOTA_NAME_MAX);
466 /* filename associated with slave index files are prefixed with the most
467 * signicant bits of the global FID */
468 sprintf(name, "0x%x-", glb_fid->f_oid);
470 iops = &parent->do_index_ops->dio_it;
471 it = iops->init(env, parent, 0);
473 OBD_FREE(name, LQUOTA_NAME_MAX);
477 rc = iops->load(env, it, 0);
480 * Iterator didn't find record with exactly the key requested.
482 * It is currently either
484 * - positioned above record with key less than
485 * requested---skip it.
487 * - or not positioned at all (is in IAM_IT_SKEWED
488 * state)---position it on the next item.
490 rc = iops->next(env, it);
498 len = iops->key_size(env, it);
499 /* IAM iterator can return record with zero len. */
500 if (len == 0 || len <= strlen(name) || len >= LQUOTA_NAME_MAX)
503 key = iops->key(env, it);
509 if (strncmp((char *)key, name, strlen(name)) != 0)
512 /* ldiskfs OSD returns filename as stored in directory entry
513 * which does not end up with '\0' */
514 memcpy(&qti->qti_buf, key, len);
515 qti->qti_buf[len] = '\0';
517 /* lookup fid associated with this slave index file */
518 rc = dt_lookup_dir(env, parent, qti->qti_buf, &qti->qti_fid);
522 if (qti->qti_fid.f_seq != FID_SEQ_QUOTA)
525 rc = func(env, glb_fid, qti->qti_buf, &qti->qti_fid, arg);
530 rc = iops->next(env, it);
531 } while (rc == -ESTALE);
536 OBD_FREE(name, LQUOTA_NAME_MAX);
543 * Retrieve quota settings from disk for a particular identifier.
545 * \param env - is the environment passed by the caller
546 * \param obj - is the on-disk index where quota settings are stored.
547 * \param id - is the key to be updated
548 * \param rec - is the output record where to store quota settings.
550 * \retval - 0 on success, appropriate error on failure
552 int lquota_disk_read(const struct lu_env *env, struct dt_object *obj,
553 union lquota_id *id, struct dt_rec *rec)
558 LASSERT(dt_object_exists(obj));
559 LASSERT(obj->do_index_ops != NULL);
561 /* lookup on-disk record from index file */
562 dt_read_lock(env, obj, 0);
563 rc = dt_lookup(env, obj, rec, (struct dt_key *)&id->qid_uid);
564 dt_read_unlock(env, obj);
570 * Reserve enough credits to update a record in a quota index file.
572 * \param env - is the environment passed by the caller
573 * \param th - is the transaction to use for disk writes
574 * \param obj - is the on-disk index where quota settings are stored.
575 * \param id - is the key to be updated
577 * \retval - 0 on success, appropriate error on failure
579 int lquota_disk_declare_write(const struct lu_env *env, struct thandle *th,
580 struct dt_object *obj, union lquota_id *id)
582 struct lquota_thread_info *qti = lquota_info(env);
583 struct dt_key *key = (struct dt_key *)&id->qid_uid;
587 LASSERT(dt_object_exists(obj));
588 LASSERT(obj->do_index_ops != NULL);
590 /* speculative delete declaration in case there is already an existing
591 * record in the index */
592 rc = dt_declare_delete(env, obj, key, th);
596 /* declare insertion of updated record */
597 rc = dt_declare_insert(env, obj, (struct dt_rec *)&qti->qti_rec, key,
602 /* we might have to update the version of the global index too */
603 rc = dt_declare_version_set(env, obj, th);
609 * Update a record in a quota index file.
611 * \param env - is the environment passed by the caller
612 * \param th - is the transaction to use for disk writes
613 * \param obj - is the on-disk index to be updated.
614 * \param id - is the key to be updated
615 * \param rec - is the input record containing the new quota settings.
616 * \param flags - can be LQUOTA_BUMP_VER or LQUOTA_SET_VER.
617 * \param ver - is the new version of the index if LQUOTA_SET_VER is set or is
618 * used to return the new version of the index when
619 * LQUOTA_BUMP_VER is set.
621 * \retval - 0 on success, appropriate error on failure
623 int lquota_disk_write(const struct lu_env *env, struct thandle *th,
624 struct dt_object *obj, union lquota_id *id,
625 struct dt_rec *rec, __u32 flags, __u64 *ver)
627 struct lquota_thread_info *qti = lquota_info(env);
628 struct dt_key *key = (struct dt_key *)&id->qid_uid;
632 LASSERT(dt_object_exists(obj));
633 LASSERT(obj->do_index_ops != NULL);
636 dt_write_lock(env, obj, 0);
638 /* check whether there is already an existing record for this ID */
639 rc = dt_lookup(env, obj, (struct dt_rec *)&qti->qti_rec, key);
641 /* delete existing record in order to replace it */
642 rc = dt_delete(env, obj, key, th);
645 } else if (rc == -ENOENT) {
646 /* probably first insert */
653 /* insert record with updated quota settings */
654 rc = dt_insert(env, obj, rec, key, th);
656 /* try to insert the old one */
657 rc = dt_insert(env, obj, (struct dt_rec *)&qti->qti_rec,
659 LASSERTF(rc == 0, "failed to insert record in quota "
661 PFID(lu_object_fid(&obj->do_lu)));
668 if (flags & LQUOTA_BUMP_VER) {
669 /* caller wants to bump the version, let's first read
671 *ver = dt_version_get(env, obj);
674 LASSERT(flags & LQUOTA_SET_VER);
676 dt_version_set(env, obj, *ver, th);
681 dt_write_unlock(env, obj);
685 int lquota_disk_delete(const struct lu_env *env, struct thandle *th,
686 struct dt_object *obj, __u64 qid, __u64 *ver)
688 struct lquota_thread_info *qti = lquota_info(env);
689 struct dt_key *key = (struct dt_key *)&qid;
694 LASSERT(dt_object_exists(obj));
695 LASSERT(obj->do_index_ops != NULL);
698 dt_write_lock(env, obj, 0);
700 /* check whether there is already an existing record for this ID */
701 rc = dt_lookup(env, obj, (struct dt_rec *)&qti->qti_rec, key);
703 rc = dt_delete(env, obj, key, th);
704 if (rc == 0 && ver != NULL) {
705 *ver = dt_version_get(env, obj);
707 dt_version_set(env, obj, *ver, th);
711 dt_write_unlock(env, obj);
716 * Update version of an index file
718 * \param env - is the environment passed by the caller
719 * \param dev - is the backend dt device storing the index file
720 * \param obj - is the on-disk index that should be updated
721 * \param ver - is the new version
723 int lquota_disk_update_ver(const struct lu_env *env, struct dt_device *dev,
724 struct dt_object *obj, __u64 ver)
730 th = dt_trans_create(env, dev);
734 rc = dt_declare_version_set(env, obj, th);
738 rc = dt_trans_start_local(env, dev, th);
743 dt_version_set(env, obj, ver, th);
746 dt_trans_stop(env, dev, th);
751 * Write a global record
753 * \param env - is the environment passed by the caller
754 * \param obj - is the on-disk global index to be updated
755 * \param id - index to be updated
756 * \param rec - record to be written
758 int lquota_disk_write_glb(const struct lu_env *env, struct dt_object *obj,
759 __u64 id, struct lquota_glb_rec *rec)
761 struct dt_device *dev = lu2dt_dev(obj->do_lu.lo_dev);
763 struct dt_key *key = (struct dt_key *)&id;
767 th = dt_trans_create(env, dev);
771 /* the entry with 0 key can always be found in IAM file. */
773 rc = dt_declare_delete(env, obj, key, th);
778 rc = dt_declare_insert(env, obj, (struct dt_rec *)rec, key, th);
782 rc = dt_trans_start_local(env, dev, th);
786 dt_write_lock(env, obj, 0);
789 struct lquota_glb_rec *tmp;
793 GOTO(out_lock, rc = -ENOMEM);
795 rc = dt_lookup(env, obj, (struct dt_rec *)tmp, key);
799 rc = dt_delete(env, obj, key, th);
805 rc = dt_insert(env, obj, (struct dt_rec *)rec, key, th);
807 dt_write_unlock(env, obj);
809 dt_trans_stop(env, dev, th);