+/**
+ * Check if it needs to update filter_fid by the value of @oa.
+ *
+ * \param[in] env env
+ * \param[in] fo ofd object
+ * \param[in] oa obdo from client or MDT
+ * \param[out] ff if filter_fid needs updating, this field is used to
+ * return the new buffer
+ *
+ * \retval < 0 error occurred
+ * \retval 0 doesn't need to update filter_fid
+ * \retval FL_XATTR_{CREATE,REPLACE} flag for xattr update
+ */
+int ofd_object_ff_update(const struct lu_env *env, struct ofd_object *fo,
+ const struct obdo *oa, struct filter_fid *ff)
+{
+ int rc = 0;
+ ENTRY;
+
+ if (!(oa->o_valid &
+ (OBD_MD_FLFID | OBD_MD_FLOSTLAYOUT | OBD_MD_LAYOUT_VERSION)))
+ RETURN(0);
+
+ rc = ofd_object_ff_load(env, fo);
+ if (rc < 0 && rc != -ENODATA)
+ RETURN(rc);
+
+ LASSERT(ff != &fo->ofo_ff);
+ if (rc == -ENODATA) {
+ rc = LU_XATTR_CREATE;
+ memset(ff, 0, sizeof(*ff));
+ } else {
+ rc = LU_XATTR_REPLACE;
+ memcpy(ff, &fo->ofo_ff, sizeof(*ff));
+ }
+
+ if (oa->o_valid & OBD_MD_FLFID) {
+ /* packing fid and converting it to LE for storing into EA.
+ * Here ->o_stripe_idx should be filled by LOV and rest of
+ * fields - by client. */
+ ff->ff_parent.f_seq = oa->o_parent_seq;
+ ff->ff_parent.f_oid = oa->o_parent_oid;
+ /* XXX: we are ignoring o_parent_ver here, since this should
+ * be the same for all objects in this fileset. */
+ ff->ff_parent.f_ver = oa->o_stripe_idx;
+ }
+ if (oa->o_valid & OBD_MD_FLOSTLAYOUT)
+ ff->ff_layout = oa->o_layout;
+
+ if (oa->o_valid & OBD_MD_LAYOUT_VERSION) {
+ CDEBUG(D_INODE, DFID": OST("DFID") layout version %u -> %u\n",
+ PFID(&fo->ofo_ff.ff_parent),
+ PFID(lu_object_fid(&fo->ofo_obj.do_lu)),
+ ff->ff_layout_version, oa->o_layout_version);
+
+ /* only the MDS has the authority to update layout version */
+ if (!(exp_connect_flags(ofd_info(env)->fti_exp) &
+ OBD_CONNECT_MDS)) {
+ CERROR(DFID": update layout version from client\n",
+ PFID(&fo->ofo_ff.ff_parent));
+
+ RETURN(-EPERM);
+ }
+
+ if (ff->ff_layout_version & LU_LAYOUT_RESYNC) {
+ /* this opens a new era of writing */
+ ff->ff_layout_version = 0;
+ ff->ff_range = 0;
+ }
+
+ /* it's not allowed to change it to a smaller value */
+ if (oa->o_layout_version < ff->ff_layout_version)
+ RETURN(-EINVAL);
+
+ if (ff->ff_layout_version == 0 ||
+ oa->o_layout_version & LU_LAYOUT_RESYNC) {
+ /* if LU_LAYOUT_RESYNC is set, it closes the era of
+ * writing. Only mirror I/O can write this object. */
+ ff->ff_layout_version = oa->o_layout_version;
+ ff->ff_range = 0;
+ } else if (oa->o_layout_version > ff->ff_layout_version) {
+ ff->ff_range = MAX(ff->ff_range,
+ oa->o_layout_version - ff->ff_layout_version);
+ }
+ }
+
+ if (memcmp(ff, &fo->ofo_ff, sizeof(*ff)))
+ filter_fid_cpu_to_le(ff, ff, sizeof(*ff));
+ else /* no change */
+ rc = 0;
+
+ RETURN(rc);
+}
+
+/**
+ * Set OFD object attributes.
+ *
+ * This function sets OFD object attributes taken from incoming request.
+ * It sets not only regular attributes but also XATTR_NAME_FID extended
+ * attribute if needed. The "fid" xattr allows the object's MDT parent inode
+ * to be found and verified by LFSCK and other tools in case of inconsistency.
+ *
+ * \param[in] env execution environment
+ * \param[in] fo OFD object
+ * \param[in] la object attributes
+ * \param[in] oa obdo carries fid, ost_layout, layout version
+ *
+ * \retval 0 if successful
+ * \retval negative value on error
+ */