+ /* XXX: this is a temporary solution to declare llog changes
+ * will be fixed in 2.3 with new llog implementation */
+
+ LASSERT(mdd->mdd_capa);
+
+ /* XXX: Since we use the 'mdd_capa' as fake llog object here, we
+ * have to set the parameter 'size' as INT_MAX or 0 to inform
+ * OSD that this record write is for a llog write or catalog
+ * header update, and osd declare function will reserve less
+ * credits for optimization purpose.
+ *
+ * Reserve 6 blocks for a llog write, since the llog file is
+ * usually small, reserve 2 blocks for catalog header update,
+ * because we know for sure that catalog header is already
+ * allocated.
+ *
+ * This hack should be removed in 2.3.
+ */
+
+ /* record itself */
+ rc = dt_declare_record_write(env, mdd->mdd_capa,
+ DECLARE_LLOG_WRITE, 0, handle);
+ if (rc)
+ return rc;
+
+ /* header will be updated as well */
+ rc = dt_declare_record_write(env, mdd->mdd_capa,
+ DECLARE_LLOG_WRITE, 0, handle);
+ if (rc)
+ return rc;
+
+ /* also we should be able to create new plain log */
+ rc = dt_declare_create(env, mdd->mdd_capa, NULL, NULL, NULL, handle);
+ if (rc)
+ return rc;
+
+ /* new record referencing new plain llog */
+ rc = dt_declare_record_write(env, mdd->mdd_capa,
+ DECLARE_LLOG_WRITE, 0, handle);
+ if (rc)
+ return rc;
+
+ /* catalog's header will be updated as well */
+ rc = dt_declare_record_write(env, mdd->mdd_capa,
+ DECLARE_LLOG_REWRITE, 0, handle);
+
+ return rc;
+}
+
+int mdd_declare_changelog_store(const struct lu_env *env,
+ struct mdd_device *mdd,
+ const struct lu_name *fname,
+ struct thandle *handle)
+{
+ struct obd_device *obd = mdd2obd_dev(mdd);
+ struct llog_ctxt *ctxt;
+ struct llog_changelog_rec *rec;
+ struct lu_buf *buf;
+ int reclen;
+ int rc;
+
+ /* Not recording */
+ if (!(mdd->mdd_cl.mc_flags & CLM_ON))
+ return 0;
+
+ reclen = llog_data_len(sizeof(*rec) +
+ (fname != NULL ? fname->ln_namelen : 0));
+ buf = mdd_buf_alloc(env, reclen);
+ if (buf->lb_buf == NULL)
+ return -ENOMEM;
+
+ rec = buf->lb_buf;
+ rec->cr_hdr.lrh_len = reclen;
+ rec->cr_hdr.lrh_type = CHANGELOG_REC;
+
+ ctxt = llog_get_context(obd, LLOG_CHANGELOG_ORIG_CTXT);
+ if (ctxt == NULL)
+ return -ENXIO;
+
+ rc = llog_declare_add(env, ctxt->loc_handle, &rec->cr_hdr, handle);
+ llog_ctxt_put(ctxt);
+
+ return rc;
+}
+
+static int mdd_declare_changelog_ext_store(const struct lu_env *env,
+ struct mdd_device *mdd,
+ const struct lu_name *tname,
+ const struct lu_name *sname,
+ struct thandle *handle)
+{
+ struct obd_device *obd = mdd2obd_dev(mdd);
+ struct llog_ctxt *ctxt;
+ struct llog_changelog_ext_rec *rec;
+ struct lu_buf *buf;
+ int reclen;
+ int rc;
+
+ /* Not recording */
+ if (!(mdd->mdd_cl.mc_flags & CLM_ON))
+ return 0;
+
+ reclen = llog_data_len(sizeof(*rec) +
+ (tname != NULL ? tname->ln_namelen : 0) +
+ (sname != NULL ? 1 + sname->ln_namelen : 0));
+ buf = mdd_buf_alloc(env, reclen);
+ if (buf->lb_buf == NULL)
+ return -ENOMEM;
+
+ rec = buf->lb_buf;
+ rec->cr_hdr.lrh_len = reclen;
+ rec->cr_hdr.lrh_type = CHANGELOG_REC;
+
+ ctxt = llog_get_context(obd, LLOG_CHANGELOG_ORIG_CTXT);
+ if (ctxt == NULL)
+ return -ENXIO;
+
+ rc = llog_declare_add(env, ctxt->loc_handle, &rec->cr_hdr, handle);
+ llog_ctxt_put(ctxt);
+
+ return rc;
+}
+
+/** Add a changelog entry \a rec to the changelog llog
+ * \param mdd
+ * \param rec
+ * \param handle - currently ignored since llogs start their own transaction;
+ * this will hopefully be fixed in llog rewrite
+ * \retval 0 ok
+ */
+int mdd_changelog_store(const struct lu_env *env, struct mdd_device *mdd,
+ struct llog_changelog_rec *rec, struct thandle *th)
+{
+ struct obd_device *obd = mdd2obd_dev(mdd);
+ struct llog_ctxt *ctxt;
+ int rc;
+
+ rec->cr_hdr.lrh_len = llog_data_len(sizeof(*rec) + rec->cr.cr_namelen);
+ rec->cr_hdr.lrh_type = CHANGELOG_REC;
+ rec->cr.cr_time = cl_time();
+
+ spin_lock(&mdd->mdd_cl.mc_lock);
+ /* NB: I suppose it's possible llog_add adds out of order wrt cr_index,
+ * but as long as the MDD transactions are ordered correctly for e.g.
+ * rename conflicts, I don't think this should matter. */
+ rec->cr.cr_index = ++mdd->mdd_cl.mc_index;
+ spin_unlock(&mdd->mdd_cl.mc_lock);
+
+ ctxt = llog_get_context(obd, LLOG_CHANGELOG_ORIG_CTXT);
+ if (ctxt == NULL)
+ return -ENXIO;
+
+ rc = llog_add(env, ctxt->loc_handle, &rec->cr_hdr, NULL, NULL, th);
+ llog_ctxt_put(ctxt);
+ if (rc > 0)
+ rc = 0;
+ return rc;
+}
+
+/** Add a changelog_ext entry \a rec to the changelog llog
+ * \param mdd
+ * \param rec
+ * \param handle - currently ignored since llogs start their own transaction;
+ * this will hopefully be fixed in llog rewrite
+ * \retval 0 ok
+ */
+int mdd_changelog_ext_store(const struct lu_env *env, struct mdd_device *mdd,
+ struct llog_changelog_ext_rec *rec,
+ struct thandle *th)
+{
+ struct obd_device *obd = mdd2obd_dev(mdd);
+ struct llog_ctxt *ctxt;
+ int rc;
+
+ rec->cr_hdr.lrh_len = llog_data_len(sizeof(*rec) + rec->cr.cr_namelen);
+ /* llog_lvfs_write_rec sets the llog tail len */
+ rec->cr_hdr.lrh_type = CHANGELOG_REC;
+ rec->cr.cr_time = cl_time();
+
+ spin_lock(&mdd->mdd_cl.mc_lock);
+ /* NB: I suppose it's possible llog_add adds out of order wrt cr_index,
+ * but as long as the MDD transactions are ordered correctly for e.g.
+ * rename conflicts, I don't think this should matter. */
+ rec->cr.cr_index = ++mdd->mdd_cl.mc_index;
+ spin_unlock(&mdd->mdd_cl.mc_lock);
+
+ ctxt = llog_get_context(obd, LLOG_CHANGELOG_ORIG_CTXT);
+ if (ctxt == NULL)
+ return -ENXIO;
+
+ /* nested journal transaction */
+ rc = llog_add(env, ctxt->loc_handle, &rec->cr_hdr, NULL, NULL, th);
+ llog_ctxt_put(ctxt);
+ if (rc > 0)
+ rc = 0;
+
+ return rc;
+}
+
+/** Store a namespace change changelog record
+ * If this fails, we must fail the whole transaction; we don't
+ * want the change to commit without the log entry.
+ * \param target - mdd_object of change
+ * \param parent - parent dir/object
+ * \param tname - target name string
+ * \param handle - transacion handle
+ */
+static int mdd_changelog_ns_store(const struct lu_env *env,
+ struct mdd_device *mdd,
+ enum changelog_rec_type type,
+ unsigned flags,
+ struct mdd_object *target,
+ struct mdd_object *parent,
+ const struct lu_name *tname,
+ struct thandle *handle)
+{
+ struct llog_changelog_rec *rec;
+ struct lu_buf *buf;
+ int reclen;
+ int rc;
+ ENTRY;
+
+ /* Not recording */
+ if (!(mdd->mdd_cl.mc_flags & CLM_ON))
+ RETURN(0);
+ if ((mdd->mdd_cl.mc_mask & (1 << type)) == 0)
+ RETURN(0);
+
+ LASSERT(target != NULL);
+ LASSERT(parent != NULL);
+ LASSERT(tname != NULL);
+ LASSERT(handle != NULL);
+
+ reclen = llog_data_len(sizeof(*rec) + tname->ln_namelen);
+ buf = mdd_buf_alloc(env, reclen);
+ if (buf->lb_buf == NULL)
+ RETURN(-ENOMEM);
+ rec = buf->lb_buf;
+
+ rec->cr.cr_flags = CLF_VERSION | (CLF_FLAGMASK & flags);
+ rec->cr.cr_type = (__u32)type;
+ rec->cr.cr_tfid = *mdo2fid(target);
+ rec->cr.cr_pfid = *mdo2fid(parent);
+ rec->cr.cr_namelen = tname->ln_namelen;
+ memcpy(rec->cr.cr_name, tname->ln_name, tname->ln_namelen);
+
+ target->mod_cltime = cfs_time_current_64();
+
+ rc = mdd_changelog_store(env, mdd, rec, handle);
+ if (rc < 0) {
+ CERROR("changelog failed: rc=%d, op%d %s c"DFID" p"DFID"\n",
+ rc, type, tname->ln_name, PFID(&rec->cr.cr_tfid),
+ PFID(&rec->cr.cr_pfid));
+ RETURN(-EFAULT);
+ }
+
+ RETURN(0);
+}
+
+
+/** Store a namespace change changelog record
+ * If this fails, we must fail the whole transaction; we don't
+ * want the change to commit without the log entry.
+ * \param target - mdd_object of change
+ * \param tpfid - target parent dir/object fid
+ * \param sfid - source object fid
+ * \param spfid - source parent fid
+ * \param tname - target name string
+ * \param sname - source name string
+ * \param handle - transacion handle
+ */
+static int mdd_changelog_ext_ns_store(const struct lu_env *env,
+ struct mdd_device *mdd,
+ enum changelog_rec_type type,
+ unsigned flags,
+ struct mdd_object *target,
+ const struct lu_fid *tpfid,
+ const struct lu_fid *sfid,
+ const struct lu_fid *spfid,
+ const struct lu_name *tname,
+ const struct lu_name *sname,
+ struct thandle *handle)
+{
+ struct llog_changelog_ext_rec *rec;
+ struct lu_buf *buf;
+ int reclen;
+ int rc;
+ ENTRY;
+
+ /* Not recording */
+ if (!(mdd->mdd_cl.mc_flags & CLM_ON))
+ RETURN(0);
+ if ((mdd->mdd_cl.mc_mask & (1 << type)) == 0)
+ RETURN(0);
+
+ LASSERT(sfid != NULL);
+ LASSERT(tpfid != NULL);
+ LASSERT(tname != NULL);
+ LASSERT(handle != NULL);
+
+ reclen = llog_data_len(sizeof(*rec) +
+ sname != NULL ? 1 + sname->ln_namelen : 0);
+ buf = mdd_buf_alloc(env, reclen);
+ if (buf->lb_buf == NULL)
+ RETURN(-ENOMEM);
+ rec = buf->lb_buf;
+
+ rec->cr.cr_flags = CLF_EXT_VERSION | (CLF_FLAGMASK & flags);
+ rec->cr.cr_type = (__u32)type;
+ rec->cr.cr_pfid = *tpfid;
+ rec->cr.cr_sfid = *sfid;
+ rec->cr.cr_spfid = *spfid;
+ rec->cr.cr_namelen = tname->ln_namelen;
+ memcpy(rec->cr.cr_name, tname->ln_name, tname->ln_namelen);
+ if (sname) {
+ LASSERT(sfid != NULL);
+ rec->cr.cr_name[tname->ln_namelen] = '\0';
+ memcpy(rec->cr.cr_name + tname->ln_namelen + 1, sname->ln_name,
+ sname->ln_namelen);
+ rec->cr.cr_namelen += 1 + sname->ln_namelen;
+ }
+
+ if (likely(target != NULL)) {
+ rec->cr.cr_tfid = *mdo2fid(target);
+ target->mod_cltime = cfs_time_current_64();
+ } else {
+ fid_zero(&rec->cr.cr_tfid);
+ }
+
+ rc = mdd_changelog_ext_store(env, mdd, rec, handle);
+ if (rc < 0) {
+ CERROR("changelog failed: rc=%d, op%d %s c"DFID" p"DFID"\n",
+ rc, type, tname->ln_name, PFID(sfid), PFID(tpfid));
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int mdd_declare_link(const struct lu_env *env,
+ struct mdd_device *mdd,
+ struct mdd_object *p,
+ struct mdd_object *c,
+ const struct lu_name *name,
+ struct thandle *handle)
+{
+ int rc;
+
+ rc = mdo_declare_index_insert(env, p, mdo2fid(c), name->ln_name,handle);
+ if (rc)
+ return rc;
+
+ rc = mdo_declare_ref_add(env, c, handle);
+ if (rc)
+ return rc;
+
+ rc = mdo_declare_attr_set(env, p, NULL, handle);
+ if (rc)
+ return rc;
+
+ rc = mdo_declare_attr_set(env, c, NULL, handle);
+ if (rc)
+ return rc;
+
+ rc = mdd_declare_links_add(env, c, handle);
+ if (rc)
+ return rc;
+
+ rc = mdd_declare_changelog_store(env, mdd, name, handle);
+
+ return rc;