+ oh = container_of0(th, struct osd_thandle, ot_super);
+ LASSERT(oh->ot_handle != NULL);
+ LASSERT(oh->ot_handle->h_transaction != NULL);
+#ifdef HAVE_QUOTA_SUPPORT
+ if (ignore_quota)
+ current->cap_effective |= CFS_CAP_SYS_RESOURCE_MASK;
+ else
+ current->cap_effective &= ~CFS_CAP_SYS_RESOURCE_MASK;
+#endif
+ rc = iam_insert(oh->ot_handle, bag, (const struct iam_key *)key,
+ (struct iam_rec *)rec, ipd);
+#ifdef HAVE_QUOTA_SUPPORT
+ current->cap_effective = save;
+#endif
+ osd_ipd_put(env, bag, ipd);
+ LINVRNT(osd_invariant(obj));
+ RETURN(rc);
+}
+
+/**
+ * Calls ldiskfs_add_dot_dotdot() to add dot and dotdot entries
+ * into the directory.Also sets flags into osd object to
+ * indicate dot and dotdot are created. This is required for
+ * interoperability mode (b11826)
+ *
+ * \param dir directory for dot and dotdot fixup.
+ * \param obj child object for linking
+ *
+ * \retval 0, on success
+ * \retval -ve, on error
+ */
+static int osd_add_dot_dotdot(struct osd_thread_info *info,
+ struct osd_object *dir,
+ struct osd_object *obj, const char *name,
+ struct thandle *th)
+{
+ struct inode *parent_dir = obj->oo_inode;
+ struct inode *inode = dir->oo_inode;
+ struct osd_thandle *oth;
+ int result = 0;
+
+ oth = container_of(th, struct osd_thandle, ot_super);
+ LASSERT(oth->ot_handle->h_transaction != NULL);
+ LASSERT(S_ISDIR(dir->oo_inode->i_mode));
+
+ if (strcmp(name, dot) == 0) {
+ if (dir->oo_compat_dot_created) {
+ result = -EEXIST;
+ } else {
+ LASSERT(obj == dir);
+ dir->oo_compat_dot_created = 1;
+ result = 0;
+ }
+ } else if(strcmp(name, dotdot) == 0) {
+ if (!dir->oo_compat_dot_created)
+ return -EINVAL;
+ if (dir->oo_compat_dotdot_created)
+ return __osd_ea_add_rec(info, dir, obj, name, th);
+
+ result = ldiskfs_add_dot_dotdot(oth->ot_handle, parent_dir, inode);
+ if (result == 0)
+ dir->oo_compat_dotdot_created = 1;
+ }
+
+ return result;
+}
+
+/**
+ * Calls ldiskfs_add_entry() to add directory entry
+ * into the directory. This is required for
+ * interoperability mode (b11826)
+ *
+ * \retval 0, on success
+ * \retval -ve, on error
+ */
+static int __osd_ea_add_rec(struct osd_thread_info *info,
+ struct osd_object *pobj,
+ struct osd_object *cobj,
+ const char *name,
+ struct thandle *th)
+{
+ struct dentry *child;
+ struct osd_thandle *oth;
+ struct inode *cinode = cobj->oo_inode;
+ int rc;
+
+ oth = container_of(th, struct osd_thandle, ot_super);
+ LASSERT(oth->ot_handle != NULL);
+ LASSERT(oth->ot_handle->h_transaction != NULL);
+
+ child = osd_child_dentry_get(info->oti_env, pobj, name, strlen(name));
+ rc = ldiskfs_add_entry(oth->ot_handle, child, cinode);
+
+ RETURN(rc);
+}
+
+/**
+ * It will call the appropriate osd_add* function and return the
+ * value, return by respective functions.
+ */
+static int osd_ea_add_rec(const struct lu_env *env,
+ struct osd_object *pobj,
+ struct osd_object *cobj,
+ const char *name,
+ struct thandle *th)
+{
+ struct osd_thread_info *info = osd_oti_get(env);
+ int rc;
+
+ if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' &&
+ name[2] =='\0')))
+ rc = osd_add_dot_dotdot(info, pobj, cobj, name, th);
+ else
+ rc = __osd_ea_add_rec(info, pobj, cobj, name, th);
+
+ return rc;
+}
+
+/**
+ * Calls ->lookup() to find dentry. From dentry get inode and
+ * read inode's ea to get fid. This is required for interoperability
+ * mode (b11826)
+ *
+ * \retval 0, on success
+ * \retval -ve, on error
+ */
+static int osd_ea_lookup_rec(const struct lu_env *env, struct osd_object *obj,
+ struct dt_rec *rec, const struct dt_key *key)
+{
+ struct inode *dir = obj->oo_inode;
+ struct osd_thread_info *info = osd_oti_get(env);
+ struct dentry *dentry;
+ struct osd_device *dev = osd_dev(obj->oo_dt.do_lu.lo_dev);
+ struct osd_inode_id *id = &info->oti_id;
+ struct ldiskfs_dir_entry_2 *de;
+ struct buffer_head *bh;
+ struct inode *inode;
+ int ino;
+ int rc;
+
+ LASSERT(dir->i_op != NULL && dir->i_op->lookup != NULL);
+
+ dentry = osd_child_dentry_get(env, obj,
+ (char *)key, strlen((char *)key));
+
+ down_read(&obj->oo_ext_idx_sem);
+ bh = ldiskfs_find_entry(dentry, &de);
+ if (bh) {
+ ino = le32_to_cpu(de->inode);
+ brelse(bh);
+ id->oii_ino = ino;
+ id->oii_gen = OSD_OII_NOGEN;
+
+ inode = osd_iget(info, dev, id);
+ if (!IS_ERR(inode)) {
+ dentry->d_inode = inode;
+
+ rc = osd_ea_fid_get(env, dentry, rec);
+ iput(inode);
+ } else
+ rc = PTR_ERR(inode);
+ } else
+ rc = -ENOENT;
+
+ up_read(&obj->oo_ext_idx_sem);
+ RETURN (rc);
+}
+
+/**
+ * Find the osd object for given fid.
+ *
+ * \param fid, need to find the osd object having this fid
+ *
+ * \retval osd_object, on success
+ * \retval -ve, on error
+ */
+struct osd_object *osd_object_find(const struct lu_env *env,
+ struct dt_object *dt,
+ const struct lu_fid *fid)
+{
+ struct lu_device *ludev = dt->do_lu.lo_dev;
+ struct osd_object *child = NULL;
+ struct lu_object *luch;
+ struct lu_object *lo;
+
+ luch = lu_object_find(env, ludev, fid, NULL);
+ if (!IS_ERR(luch)) {
+ if (lu_object_exists(luch)) {
+ lo = lu_object_locate(luch->lo_header, ludev->ld_type);
+ if (lo != NULL)
+ child = osd_obj(lo);
+ else
+ LU_OBJECT_DEBUG(D_ERROR, env, luch,
+ "lu_object can't be located"
+ ""DFID"\n", PFID(fid));
+
+ if (child == NULL) {
+ lu_object_put(env, luch);
+ CERROR("Unable to get osd_object\n");
+ child = ERR_PTR(-ENOENT);
+ }
+ } else {
+ LU_OBJECT_DEBUG(D_ERROR, env, luch,
+ "lu_object does not exists "DFID"\n",
+ PFID(fid));
+ child = ERR_PTR(-ENOENT);
+ }
+ } else
+ child = (void *)luch;
+
+ return child;
+}
+
+/**
+ * Put the osd object once done with it.
+ *
+ * \param obj, osd object that needs to be put
+ */
+static inline void osd_object_put(const struct lu_env *env,
+ struct osd_object *obj)
+{
+ lu_object_put(env, &obj->oo_dt.do_lu);
+}
+
+/**
+ * Index add function for interoperability mode (b11826).
+ * It will add the directory entry.This entry is needed to
+ * maintain name->fid mapping.
+ *
+ * \param key, it is key i.e. file entry to be inserted
+ * \param rec, it is value of given key i.e. fid
+ *
+ * \retval 0, on success
+ * \retval -ve, on error
+ */
+static int osd_index_ea_insert(const struct lu_env *env, struct dt_object *dt,
+ const struct dt_rec *rec,
+ const struct dt_key *key, struct thandle *th,
+ struct lustre_capa *capa, int ignore_quota)
+{
+ struct osd_object *obj = osd_dt_obj(dt);
+ struct lu_fid *fid = &osd_oti_get(env)->oti_fid;
+ const struct lu_fid_pack *pack = (const struct lu_fid_pack *)rec;
+ const char *name = (const char *)key;
+ struct osd_object *child;
+#ifdef HAVE_QUOTA_SUPPORT
+ cfs_cap_t save = current->cap_effective;
+#endif
+ int rc;
+
+ ENTRY;
+
+ LASSERT(osd_invariant(obj));
+ LASSERT(dt_object_exists(dt));
+ LASSERT(th != NULL);
+
+ if (osd_object_auth(env, dt, capa, CAPA_OPC_INDEX_INSERT))
+ RETURN(-EACCES);
+
+ rc = fid_unpack(pack, fid);
+ if (rc != 0)
+ RETURN(rc);
+ child = osd_object_find(env, dt, fid);
+ if (!IS_ERR(child)) {
+ struct inode *inode = obj->oo_inode;
+ struct osd_thread_info *oti = osd_oti_get(env);
+ struct timespec *ctime = &oti->oti_time;
+ struct timespec *mtime = &oti->oti_time2;
+
+ *ctime = inode->i_ctime;
+ *mtime = inode->i_mtime;
+#ifdef HAVE_QUOTA_SUPPORT
+ if (ignore_quota)
+ current->cap_effective |= CFS_CAP_SYS_RESOURCE_MASK;
+ else
+ current->cap_effective &= ~CFS_CAP_SYS_RESOURCE_MASK;
+#endif
+ down_write(&obj->oo_ext_idx_sem);
+ rc = osd_ea_add_rec(env, obj, child, name, th);
+ up_write(&obj->oo_ext_idx_sem);
+#ifdef HAVE_QUOTA_SUPPORT
+ current->cap_effective = save;
+#endif
+ osd_object_put(env, child);
+ /* xtime should not be updated with server-side time. */
+ spin_lock(&obj->oo_guard);
+ inode->i_ctime = *ctime;
+ inode->i_mtime = *mtime;
+ spin_unlock(&obj->oo_guard);
+ mark_inode_dirty(inode);
+ } else {
+ rc = PTR_ERR(child);
+ }
+