+ * \retval = 0 get the entry successfully
+ * negative errno (< 0) does not get the entry
+ */
+static int lmv_get_min_striped_entry(struct obd_export *exp,
+ struct md_op_data *op_data,
+ struct md_callback *cb_op,
+ __u64 hash_offset, int *stripe_offset,
+ struct lu_dirent **entp,
+ struct page **ppage)
+{
+ struct obd_device *obd = exp->exp_obd;
+ struct lmv_obd *lmv = &obd->u.lmv;
+ struct lmv_stripe_md *lsm = op_data->op_mea1;
+ struct lmv_tgt_desc *tgt;
+ int stripe_count;
+ struct lu_dirent *min_ent = NULL;
+ struct page *min_page = NULL;
+ int min_idx = 0;
+ int i;
+ int rc = 0;
+ ENTRY;
+
+ stripe_count = lsm->lsm_md_stripe_count;
+ for (i = 0; i < stripe_count; i++) {
+ struct lu_dirent *ent = NULL;
+ struct page *page = NULL;
+ struct lu_dirpage *dp;
+ __u64 stripe_hash = hash_offset;
+
+ tgt = lmv_get_target(lmv, lsm->lsm_md_oinfo[i].lmo_mds, NULL);
+ if (IS_ERR(tgt))
+ GOTO(out, rc = PTR_ERR(tgt));
+
+ /* op_data will be shared by each stripe, so we need
+ * reset these value for each stripe */
+ op_data->op_fid1 = lsm->lsm_md_oinfo[i].lmo_fid;
+ op_data->op_fid2 = lsm->lsm_md_oinfo[i].lmo_fid;
+ op_data->op_data = lsm->lsm_md_oinfo[i].lmo_root;
+next:
+ rc = md_read_page(tgt->ltd_exp, op_data, cb_op, stripe_hash,
+ &page);
+ if (rc != 0)
+ GOTO(out, rc);
+
+ dp = page_address(page);
+ for (ent = lu_dirent_start(dp); ent != NULL;
+ ent = lu_dirent_next(ent)) {
+ /* Skip dummy entry */
+ if (le16_to_cpu(ent->lde_namelen) == 0)
+ continue;
+
+ if (le64_to_cpu(ent->lde_hash) < hash_offset)
+ continue;
+
+ if (le64_to_cpu(ent->lde_hash) == hash_offset &&
+ (*entp == ent || i < *stripe_offset))
+ continue;
+
+ /* skip . and .. for other stripes */
+ if (i != 0 &&
+ (strncmp(ent->lde_name, ".",
+ le16_to_cpu(ent->lde_namelen)) == 0 ||
+ strncmp(ent->lde_name, "..",
+ le16_to_cpu(ent->lde_namelen)) == 0))
+ continue;
+ break;
+ }
+
+ if (ent == NULL) {
+ stripe_hash = le64_to_cpu(dp->ldp_hash_end);
+
+ kunmap(page);
+ page_cache_release(page);
+ page = NULL;
+
+ /* reach the end of current stripe, go to next stripe */
+ if (stripe_hash == MDS_DIR_END_OFF)
+ continue;
+ else
+ goto next;
+ }
+
+ if (min_ent != NULL) {
+ if (le64_to_cpu(min_ent->lde_hash) >
+ le64_to_cpu(ent->lde_hash)) {
+ min_ent = ent;
+ kunmap(min_page);
+ page_cache_release(min_page);
+ min_idx = i;
+ min_page = page;
+ } else {
+ kunmap(page);
+ page_cache_release(page);
+ page = NULL;
+ }
+ } else {
+ min_ent = ent;
+ min_page = page;
+ min_idx = i;
+ }
+ }
+
+out:
+ if (*ppage != NULL) {
+ kunmap(*ppage);
+ page_cache_release(*ppage);
+ }
+ *stripe_offset = min_idx;
+ *entp = min_ent;
+ *ppage = min_page;
+ RETURN(rc);
+}
+
+/**
+ * Build dir entry page from a striped directory