+/**
+ * Implementation of dt_index_operations:: dio_it.init
+ *
+ * This function is to initialize the iterator for striped directory,
+ * basically these lod_striped_it_xxx will just locate the stripe
+ * and call the correspondent api of its next lower layer.
+ *
+ * \param[in] env execution environment.
+ * \param[in] dt the striped directory object to be iterated.
+ * \param[in] attr the attribute of iterator, mostly used to indicate
+ * the entry attribute in the object to be iterated.
+ * \param[in] capa capability(useless in current implementation)
+ *
+ * \retval initialized iterator(dt_it) if successful initialize the
+ * iteration. lit_stripe_index will be used to indicate the
+ * current iterate position among stripes.
+ * \retval ERR pointer if initialization is failed.
+ */
+static struct dt_it *lod_striped_it_init(const struct lu_env *env,
+ struct dt_object *dt, __u32 attr,
+ struct lustre_capa *capa)
+{
+ struct lod_object *lo = lod_dt_obj(dt);
+ struct dt_object *next;
+ struct lod_it *it = &lod_env_info(env)->lti_it;
+ struct dt_it *it_next;
+ ENTRY;
+
+ LASSERT(lo->ldo_stripenr > 0);
+ next = lo->ldo_stripe[0];
+ LASSERT(next != NULL);
+ LASSERT(next->do_index_ops != NULL);
+
+ it_next = next->do_index_ops->dio_it.init(env, next, attr, capa);
+ if (IS_ERR(it_next))
+ return it_next;
+
+ /* currently we do not use more than one iterator per thread
+ * so we store it in thread info. if at some point we need
+ * more active iterators in a single thread, we can allocate
+ * additional ones */
+ LASSERT(it->lit_obj == NULL);
+
+ it->lit_stripe_index = 0;
+ it->lit_attr = attr;
+ it->lit_it = it_next;
+ it->lit_obj = dt;
+
+ return (struct dt_it *)it;
+}
+
+#define LOD_CHECK_STRIPED_IT(env, it, lo) \
+do { \
+ LASSERT((it)->lit_obj != NULL); \
+ LASSERT((it)->lit_it != NULL); \
+ LASSERT((lo)->ldo_stripenr > 0); \
+ LASSERT((it)->lit_stripe_index < (lo)->ldo_stripenr); \
+} while (0)
+
+/**
+ * Implementation of dt_index_operations:: dio_it.fini
+ *
+ * This function is to finish the iterator for striped directory.
+ *
+ * \param[in] env execution environment.
+ * \param[in] di the iterator for the striped directory
+ *
+ */
+static void lod_striped_it_fini(const struct lu_env *env, struct dt_it *di)
+{
+ struct lod_it *it = (struct lod_it *)di;
+ struct lod_object *lo = lod_dt_obj(it->lit_obj);
+ struct dt_object *next;
+
+ LOD_CHECK_STRIPED_IT(env, it, lo);
+
+ next = lo->ldo_stripe[it->lit_stripe_index];
+ LASSERT(next != NULL);
+ LASSERT(next->do_index_ops != NULL);
+
+ next->do_index_ops->dio_it.fini(env, it->lit_it);
+
+ /* the iterator not in use any more */
+ it->lit_obj = NULL;
+ it->lit_it = NULL;
+ it->lit_stripe_index = 0;
+}
+
+/**
+ * Implementation of dt_index_operations:: dio_it.get
+ *
+ * This function is to position the iterator with given key
+ *
+ * \param[in] env execution environment.
+ * \param[in] di the iterator for striped directory.
+ * \param[in] key the key the iterator will be positioned.
+ *
+ * \retval 0 if successfully position iterator by the key.
+ * \retval negative error if position is failed.
+ */
+static int lod_striped_it_get(const struct lu_env *env, struct dt_it *di,
+ const struct dt_key *key)
+{
+ const struct lod_it *it = (const struct lod_it *)di;
+ struct lod_object *lo = lod_dt_obj(it->lit_obj);
+ struct dt_object *next;
+ ENTRY;
+
+ LOD_CHECK_STRIPED_IT(env, it, lo);
+
+ next = lo->ldo_stripe[it->lit_stripe_index];
+ LASSERT(next != NULL);
+ LASSERT(next->do_index_ops != NULL);
+
+ return next->do_index_ops->dio_it.get(env, it->lit_it, key);
+}
+
+/**
+ * Implementation of dt_index_operations:: dio_it.put
+ *
+ * This function is supposed to be the pair of it_get, but currently do
+ * nothing. see (osd_it_ea_put or osd_index_it_put)
+ */
+static void lod_striped_it_put(const struct lu_env *env, struct dt_it *di)
+{
+ struct lod_it *it = (struct lod_it *)di;
+ struct lod_object *lo = lod_dt_obj(it->lit_obj);
+ struct dt_object *next;
+
+ LOD_CHECK_STRIPED_IT(env, it, lo);
+
+ next = lo->ldo_stripe[it->lit_stripe_index];
+ LASSERT(next != NULL);
+ LASSERT(next->do_index_ops != NULL);
+
+ return next->do_index_ops->dio_it.put(env, it->lit_it);
+}
+
+/**
+ * Implementation of dt_index_operations:: dio_it.next
+ *
+ * This function is to position the iterator to the next entry, if current
+ * stripe is finished by checking the return value of next() in current
+ * stripe. it will go to next stripe. In the mean time, the sub-iterator
+ * for next stripe needs to be initialized.
+ *
+ * \param[in] env execution environment.
+ * \param[in] di the iterator for striped directory.
+ *
+ * \retval 0 if successfully position iterator to the next entry.
+ * \retval negative error if position is failed.
+ */
+static int lod_striped_it_next(const struct lu_env *env, struct dt_it *di)
+{
+ struct lod_it *it = (struct lod_it *)di;
+ struct lod_object *lo = lod_dt_obj(it->lit_obj);
+ struct dt_object *next;
+ struct dt_it *it_next;
+ int rc;
+ ENTRY;
+
+ LOD_CHECK_STRIPED_IT(env, it, lo);
+
+ next = lo->ldo_stripe[it->lit_stripe_index];
+ LASSERT(next != NULL);
+ LASSERT(next->do_index_ops != NULL);
+again:
+ rc = next->do_index_ops->dio_it.next(env, it->lit_it);
+ if (rc < 0)
+ RETURN(rc);
+
+ if (rc == 0 && it->lit_stripe_index == 0)
+ RETURN(rc);
+
+ if (rc == 0 && it->lit_stripe_index > 0) {
+ struct lu_dirent *ent;
+
+ ent = (struct lu_dirent *)lod_env_info(env)->lti_key;
+
+ rc = next->do_index_ops->dio_it.rec(env, it->lit_it,
+ (struct dt_rec *)ent,
+ it->lit_attr);
+ if (rc != 0)
+ RETURN(rc);
+
+ /* skip . and .. for slave stripe */
+ if ((strncmp(ent->lde_name, ".",
+ le16_to_cpu(ent->lde_namelen)) == 0 &&
+ le16_to_cpu(ent->lde_namelen) == 1) ||
+ (strncmp(ent->lde_name, "..",
+ le16_to_cpu(ent->lde_namelen)) == 0 &&
+ le16_to_cpu(ent->lde_namelen) == 2))
+ goto again;
+
+ RETURN(rc);
+ }
+
+ /* go to next stripe */
+ if (it->lit_stripe_index + 1 >= lo->ldo_stripenr)
+ RETURN(1);
+
+ it->lit_stripe_index++;
+
+ next->do_index_ops->dio_it.put(env, it->lit_it);
+ next->do_index_ops->dio_it.fini(env, it->lit_it);
+
+ rc = next->do_ops->do_index_try(env, next, &dt_directory_features);
+ if (rc != 0)
+ RETURN(rc);
+
+ next = lo->ldo_stripe[it->lit_stripe_index];
+ LASSERT(next != NULL);
+ LASSERT(next->do_index_ops != NULL);
+
+ it_next = next->do_index_ops->dio_it.init(env, next, it->lit_attr,
+ BYPASS_CAPA);
+ if (!IS_ERR(it_next)) {
+ it->lit_it = it_next;
+ goto again;
+ } else {
+ rc = PTR_ERR(it_next);
+ }
+
+ RETURN(rc);
+}
+
+/**
+ * Implementation of dt_index_operations:: dio_it.key
+ *
+ * This function is to get the key of the iterator at current position.
+ *
+ * \param[in] env execution environment.
+ * \param[in] di the iterator for striped directory.
+ *
+ * \retval key(dt_key) if successfully get the key.
+ * \retval negative error if can not get the key.
+ */
+static struct dt_key *lod_striped_it_key(const struct lu_env *env,
+ const struct dt_it *di)
+{
+ const struct lod_it *it = (const struct lod_it *)di;
+ struct lod_object *lo = lod_dt_obj(it->lit_obj);
+ struct dt_object *next;
+
+ LOD_CHECK_STRIPED_IT(env, it, lo);
+
+ next = lo->ldo_stripe[it->lit_stripe_index];
+ LASSERT(next != NULL);
+ LASSERT(next->do_index_ops != NULL);
+
+ return next->do_index_ops->dio_it.key(env, it->lit_it);
+}
+
+/**
+ * Implementation of dt_index_operations:: dio_it.key_size
+ *
+ * This function is to get the key_size of current key.
+ *
+ * \param[in] env execution environment.
+ * \param[in] di the iterator for striped directory.
+ *
+ * \retval key_size if successfully get the key_size.
+ * \retval negative error if can not get the key_size.
+ */
+static int lod_striped_it_key_size(const struct lu_env *env,
+ const struct dt_it *di)
+{
+ struct lod_it *it = (struct lod_it *)di;
+ struct lod_object *lo = lod_dt_obj(it->lit_obj);
+ struct dt_object *next;
+
+ LOD_CHECK_STRIPED_IT(env, it, lo);
+
+ next = lo->ldo_stripe[it->lit_stripe_index];
+ LASSERT(next != NULL);
+ LASSERT(next->do_index_ops != NULL);
+
+ return next->do_index_ops->dio_it.key_size(env, it->lit_it);
+}
+
+/**
+ * Implementation of dt_index_operations:: dio_it.rec
+ *
+ * This function is to get the record at current position.
+ *
+ * \param[in] env execution environment.
+ * \param[in] di the iterator for striped directory.
+ * \param[in] attr the attribute of iterator, mostly used to indicate
+ * the entry attribute in the object to be iterated.
+ * \param[out] rec hold the return record.
+ *
+ * \retval 0 if successfully get the entry.
+ * \retval negative error if can not get entry.
+ */
+static int lod_striped_it_rec(const struct lu_env *env, const struct dt_it *di,
+ struct dt_rec *rec, __u32 attr)
+{
+ const struct lod_it *it = (const struct lod_it *)di;
+ struct lod_object *lo = lod_dt_obj(it->lit_obj);
+ struct dt_object *next;
+
+ LOD_CHECK_STRIPED_IT(env, it, lo);
+
+ next = lo->ldo_stripe[it->lit_stripe_index];
+ LASSERT(next != NULL);
+ LASSERT(next->do_index_ops != NULL);
+
+ return next->do_index_ops->dio_it.rec(env, it->lit_it, rec, attr);
+}
+
+/**
+ * Implementation of dt_index_operations:: dio_it.rec_size
+ *
+ * This function is to get the record_size at current record.
+ *
+ * \param[in] env execution environment.
+ * \param[in] di the iterator for striped directory.
+ * \param[in] attr the attribute of iterator, mostly used to indicate
+ * the entry attribute in the object to be iterated.
+ *
+ * \retval rec_size if successfully get the entry size.
+ * \retval negative error if can not get entry size.
+ */
+static int lod_striped_it_rec_size(const struct lu_env *env,
+ const struct dt_it *di, __u32 attr)
+{
+ struct lod_it *it = (struct lod_it *)di;
+ struct lod_object *lo = lod_dt_obj(it->lit_obj);
+ struct dt_object *next;
+
+ LOD_CHECK_STRIPED_IT(env, it, lo);
+
+ next = lo->ldo_stripe[it->lit_stripe_index];
+ LASSERT(next != NULL);
+ LASSERT(next->do_index_ops != NULL);
+
+ return next->do_index_ops->dio_it.rec_size(env, it->lit_it, attr);
+}
+
+/**
+ * Implementation of dt_index_operations:: dio_it.store
+ *
+ * This function will a cookie for current position of the iterator head,
+ * so that user can use this cookie to load/start the iterator next time.
+ *
+ * \param[in] env execution environment.
+ * \param[in] di the iterator for striped directory.
+ *
+ * \retval the cookie.
+ */
+static __u64 lod_striped_it_store(const struct lu_env *env,
+ const struct dt_it *di)
+{
+ const struct lod_it *it = (const struct lod_it *)di;
+ struct lod_object *lo = lod_dt_obj(it->lit_obj);
+ struct dt_object *next;
+
+ LOD_CHECK_STRIPED_IT(env, it, lo);
+
+ next = lo->ldo_stripe[it->lit_stripe_index];
+ LASSERT(next != NULL);
+ LASSERT(next->do_index_ops != NULL);
+
+ return next->do_index_ops->dio_it.store(env, it->lit_it);
+}
+
+/**
+ * Implementation of dt_index_operations:: dio_it.load
+ *
+ * This function will position the iterator with the given hash(usually
+ * get from store),
+ *
+ * \param[in] env execution environment.
+ * \param[in] di the iterator for striped directory.
+ * \param[in] hash the given hash.
+ *
+ * \retval >0 if successfuly load the iterator to the given position.
+ * \retval <0 if load is failed.
+ */
+static int lod_striped_it_load(const struct lu_env *env,
+ const struct dt_it *di, __u64 hash)
+{
+ const struct lod_it *it = (const struct lod_it *)di;
+ struct lod_object *lo = lod_dt_obj(it->lit_obj);
+ struct dt_object *next;
+
+ LOD_CHECK_STRIPED_IT(env, it, lo);
+
+ next = lo->ldo_stripe[it->lit_stripe_index];
+ LASSERT(next != NULL);
+ LASSERT(next->do_index_ops != NULL);
+
+ return next->do_index_ops->dio_it.load(env, it->lit_it, hash);
+}
+
+static struct dt_index_operations lod_striped_index_ops = {
+ .dio_lookup = lod_index_lookup,
+ .dio_declare_insert = lod_declare_index_insert,
+ .dio_insert = lod_index_insert,
+ .dio_declare_delete = lod_declare_index_delete,
+ .dio_delete = lod_index_delete,
+ .dio_it = {
+ .init = lod_striped_it_init,
+ .fini = lod_striped_it_fini,
+ .get = lod_striped_it_get,
+ .put = lod_striped_it_put,
+ .next = lod_striped_it_next,
+ .key = lod_striped_it_key,
+ .key_size = lod_striped_it_key_size,
+ .rec = lod_striped_it_rec,
+ .rec_size = lod_striped_it_rec_size,
+ .store = lod_striped_it_store,
+ .load = lod_striped_it_load,
+ }
+};
+
+/**
+ * Implementation of dt_object_operations:: do_index_try
+ *
+ * This function will try to initialize the index api pointer for the
+ * given object, usually it the entry point of the index api. i.e.
+ * the index object should be initialized in index_try, then start
+ * using index api. For striped directory, it will try to initialize
+ * all of its sub_stripes.
+ *
+ * \param[in] env execution environment.
+ * \param[in] dt the index object to be initialized.
+ * \param[in] feat the features of this object, for example fixed or
+ * variable key size etc.
+ *
+ * \retval >0 if the initialization is successful.
+ * \retval <0 if the initialization is failed.
+ */
+static int lod_index_try(const struct lu_env *env, struct dt_object *dt,
+ const struct dt_index_features *feat)
+{
+ struct lod_object *lo = lod_dt_obj(dt);
+ struct dt_object *next = dt_object_child(dt);
+ int rc;
+ ENTRY;
+
+ LASSERT(next->do_ops);
+ LASSERT(next->do_ops->do_index_try);
+
+ rc = lod_load_striping_locked(env, lo);
+ if (rc != 0)
+ RETURN(rc);
+
+ rc = next->do_ops->do_index_try(env, next, feat);
+ if (rc != 0)
+ RETURN(rc);
+
+ if (lo->ldo_stripenr > 0) {
+ int i;
+
+ for (i = 0; i < lo->ldo_stripenr; i++) {
+ if (dt_object_exists(lo->ldo_stripe[i]) == 0)
+ continue;
+ rc = lo->ldo_stripe[i]->do_ops->do_index_try(env,
+ lo->ldo_stripe[i], feat);
+ if (rc != 0)
+ RETURN(rc);
+ }
+ dt->do_index_ops = &lod_striped_index_ops;
+ } else {
+ dt->do_index_ops = &lod_index_ops;
+ }
+
+ RETURN(rc);
+}
+