+ struct mdd_device *mdd = (struct mdd_device *)thread->mgt_data;
+ struct dt_object *dor = mdd->mdd_orphans;
+ struct lu_dirent *ent = &mdd_env_info(env)->mti_ent;
+ const struct dt_it_ops *iops;
+ struct dt_it *it;
+ struct lu_fid fid;
+ int key_sz = 0;
+ int rc;
+ __u64 cookie;
+ ENTRY;
+
+ iops = &dor->do_index_ops->dio_it;
+ it = iops->init(env, dor, LUDA_64BITHASH);
+ if (IS_ERR(it)) {
+ rc = PTR_ERR(it);
+ CERROR("%s: cannot clean '%s': rc = %d\n",
+ mdd2obd_dev(mdd)->obd_name, mdd_orphan_index_name, rc);
+ GOTO(out, rc);
+ }
+
+ rc = iops->load(env, it, 0);
+ if (rc < 0)
+ GOTO(out_put, rc);
+ if (rc == 0) {
+ CERROR("%s: error loading iterator to clean '%s'\n",
+ mdd2obd_dev(mdd)->obd_name, mdd_orphan_index_name);
+ /* Index contains no zero key? */
+ GOTO(out_put, rc = -EIO);
+ }
+
+ do {
+ if (thread->mgt_abort)
+ break;
+
+ key_sz = iops->key_size(env, it);
+ /* filter out "." and ".." entries from PENDING dir. */
+ if (key_sz < 8)
+ goto next;
+
+ rc = iops->rec(env, it, (struct dt_rec *)ent, LUDA_64BITHASH);
+ if (rc != 0) {
+ CERROR("%s: fail to get FID for orphan it: rc = %d\n",
+ mdd2obd_dev(mdd)->obd_name, rc);
+ goto next;
+ }
+
+ fid_le_to_cpu(&fid, &ent->lde_fid);
+ if (!fid_is_sane(&fid)) {
+ CERROR("%s: bad FID "DFID" cleaning '%s'\n",
+ mdd2obd_dev(mdd)->obd_name, PFID(&fid),
+ mdd_orphan_index_name);
+ goto next;
+ }
+
+ /* kill orphan object */
+ cookie = iops->store(env, it);
+ iops->put(env, it);
+ rc = mdd_orphan_key_test_and_delete(env, mdd, &fid,
+ (struct dt_key *)ent->lde_name);
+
+ /* after index delete reset iterator */
+ if (rc == 0)
+ rc = iops->get(env, it, (const void *)"");
+ else
+ rc = iops->load(env, it, cookie);
+next:
+ rc = iops->next(env, it);
+ } while (rc == 0);
+
+ GOTO(out_put, rc = 0);
+out_put:
+ iops->put(env, it);
+ iops->fini(env, it);
+
+out:
+ return rc;
+}
+
+/**
+ * open the PENDING directory for device \a mdd
+ *
+ * The PENDING directory persistently tracks files and directories that were
+ * unlinked from the namespace (nlink == 0) but are still held open by clients.
+ * Those inodes shouldn't be deleted if the MDS crashes, because the clients
+ * would not be able to recover and reopen those files. Instead, these inodes
+ * are linked into the PENDING directory on disk, and only deleted if all
+ * clients close them, or the MDS finishes client recovery without any client
+ * reopening them (i.e. former clients didn't join recovery).
+ * \param d mdd device being started.
+ *
+ * \retval 0 success
+ * \retval -ve index operation error.
+ *
+ */
+int mdd_orphan_index_init(const struct lu_env *env, struct mdd_device *mdd)
+{
+ struct lu_fid fid;
+ struct dt_object *d;
+ int rc = 0;
+
+ ENTRY;
+
+ /* create PENDING dir */
+ fid_zero(&fid);
+ rc = mdd_local_file_create(env, mdd, &mdd->mdd_local_root_fid,
+ mdd_orphan_index_name, S_IFDIR | S_IRUGO |
+ S_IWUSR | S_IXUGO, &fid);
+ if (rc < 0)
+ RETURN(rc);
+
+ d = dt_locate(env, mdd->mdd_child, &fid);
+ if (IS_ERR(d))
+ RETURN(PTR_ERR(d));
+ LASSERT(lu_object_exists(&d->do_lu));
+ if (!dt_try_as_dir(env, d)) {
+ CERROR("%s: orphan dir '%s' is not an index: rc = %d\n",
+ mdd2obd_dev(mdd)->obd_name, mdd_orphan_index_name, rc);
+ dt_object_put(env, d);
+ RETURN(-ENOTDIR);
+ }
+ mdd->mdd_orphans = d;
+ RETURN(0);