-int mdd_links_new(const struct lu_env *env, struct mdd_link_data *ldata)
-{
- ldata->ml_buf = mdd_buf_alloc(env, CFS_PAGE_SIZE);
- if (ldata->ml_buf->lb_buf == NULL)
- return -ENOMEM;
- ldata->ml_leh = ldata->ml_buf->lb_buf;
- ldata->ml_leh->leh_magic = LINK_EA_MAGIC;
- ldata->ml_leh->leh_len = sizeof(struct link_ea_header);
- ldata->ml_leh->leh_reccount = 0;
- return 0;
-}
-
-/** Read the link EA into a temp buffer.
- * Uses the mdd_thread_info::mti_big_buf since it is generally large.
- * A pointer to the buffer is stored in \a ldata::ml_buf.
- *
- * \retval 0 or error
- */
-int mdd_links_read(const struct lu_env *env, struct mdd_object *mdd_obj,
- struct mdd_link_data *ldata)
-{
- struct lustre_capa *capa;
- struct link_ea_header *leh;
- int rc;
-
- /* First try a small buf */
- LASSERT(env != NULL);
- ldata->ml_buf = mdd_buf_alloc(env, CFS_PAGE_SIZE);
- if (ldata->ml_buf->lb_buf == NULL)
- return -ENOMEM;
-
- if (!mdd_object_exists(mdd_obj))
- return -ENODATA;
-
- capa = mdd_object_capa(env, mdd_obj);
- rc = mdo_xattr_get(env, mdd_obj, ldata->ml_buf,
- XATTR_NAME_LINK, capa);
- if (rc == -ERANGE) {
- /* Buf was too small, figure out what we need. */
- mdd_buf_put(ldata->ml_buf);
- rc = mdo_xattr_get(env, mdd_obj, ldata->ml_buf,
- XATTR_NAME_LINK, capa);
- if (rc < 0)
- return rc;
- ldata->ml_buf = mdd_buf_alloc(env, rc);
- if (ldata->ml_buf->lb_buf == NULL)
- return -ENOMEM;
- rc = mdo_xattr_get(env, mdd_obj, &LU_BUF_NULL,
- XATTR_NAME_LINK, capa);
- }
- if (rc < 0)
- return rc;
-
- leh = ldata->ml_buf->lb_buf;
- if (leh->leh_magic == __swab32(LINK_EA_MAGIC)) {
- leh->leh_magic = LINK_EA_MAGIC;
- leh->leh_reccount = __swab32(leh->leh_reccount);
- leh->leh_len = __swab64(leh->leh_len);
- /* entries are swabbed by mdd_lee_unpack */
- }
- if (leh->leh_magic != LINK_EA_MAGIC)
- return -EINVAL;
- if (leh->leh_reccount == 0)
- return -ENODATA;
-
- ldata->ml_leh = leh;
- return 0;
-}
-
-/** Read the link EA into a temp buffer.
- * Uses the name_buf since it is generally large.
- * \retval IS_ERR err
- * \retval ptr to \a lu_buf (always \a mti_big_buf)
- */
-struct lu_buf *mdd_links_get(const struct lu_env *env,
- struct mdd_object *mdd_obj)
-{
- struct mdd_link_data ldata = { 0 };
- int rc;
-
- rc = mdd_links_read(env, mdd_obj, &ldata);
- return rc ? ERR_PTR(rc) : ldata.ml_buf;
-}
-
-int mdd_links_write(const struct lu_env *env, struct mdd_object *mdd_obj,
- struct mdd_link_data *ldata, struct thandle *handle)
-{
- const struct lu_buf *buf = mdd_buf_get_const(env, ldata->ml_buf->lb_buf,
- ldata->ml_leh->leh_len);
- return mdo_xattr_set(env, mdd_obj, buf, XATTR_NAME_LINK, 0, handle,
- mdd_object_capa(env, mdd_obj));
-}
-
-/** Pack a link_ea_entry.
- * All elements are stored as chars to avoid alignment issues.
- * Numbers are always big-endian
- * \retval record length
- */
-static int mdd_lee_pack(struct link_ea_entry *lee, const struct lu_name *lname,
- const struct lu_fid *pfid)
-{
- struct lu_fid tmpfid;
- int reclen;
-
- fid_cpu_to_be(&tmpfid, pfid);
- if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_LINKEA_CRASH))
- tmpfid.f_ver = ~0;
- memcpy(&lee->lee_parent_fid, &tmpfid, sizeof(tmpfid));
- memcpy(lee->lee_name, lname->ln_name, lname->ln_namelen);
- reclen = sizeof(struct link_ea_entry) + lname->ln_namelen;
-
- lee->lee_reclen[0] = (reclen >> 8) & 0xff;
- lee->lee_reclen[1] = reclen & 0xff;
- return reclen;
-}
-
-void mdd_lee_unpack(const struct link_ea_entry *lee, int *reclen,
- struct lu_name *lname, struct lu_fid *pfid)
-{
- *reclen = (lee->lee_reclen[0] << 8) | lee->lee_reclen[1];
- memcpy(pfid, &lee->lee_parent_fid, sizeof(*pfid));
- fid_be_to_cpu(pfid, pfid);
- lname->ln_name = lee->lee_name;
- lname->ln_namelen = *reclen - sizeof(struct link_ea_entry);
-}
-
-int mdd_declare_links_add(const struct lu_env *env,
- struct mdd_object *mdd_obj,
- struct thandle *handle)
-{
- int rc;
-
- /* XXX: max size? */
- rc = mdo_declare_xattr_set(env, mdd_obj,
- mdd_buf_get_const(env, NULL, 4096),
- XATTR_NAME_LINK, 0, handle);
-
- return rc;
-}
-
-/** Add a record to the end of link ea buf */
-int mdd_links_add_buf(const struct lu_env *env, struct mdd_link_data *ldata,
- const struct lu_name *lname, const struct lu_fid *pfid)
-{
- LASSERT(ldata->ml_leh != NULL);
-
- if (lname == NULL || pfid == NULL)
- return -EINVAL;
-
- ldata->ml_reclen = lname->ln_namelen + sizeof(struct link_ea_entry);
- if (ldata->ml_leh->leh_len + ldata->ml_reclen >
- ldata->ml_buf->lb_len) {
- if (mdd_buf_grow(env, ldata->ml_leh->leh_len +
- ldata->ml_reclen) < 0)
- return -ENOMEM;
- }
-
- ldata->ml_leh = ldata->ml_buf->lb_buf;
- ldata->ml_lee = ldata->ml_buf->lb_buf + ldata->ml_leh->leh_len;
- ldata->ml_reclen = mdd_lee_pack(ldata->ml_lee, lname, pfid);
- ldata->ml_leh->leh_len += ldata->ml_reclen;
- ldata->ml_leh->leh_reccount++;
- CDEBUG(D_INODE, "New link_ea name '%.*s' is added\n",
- lname->ln_namelen, lname->ln_name);
- return 0;
-}
-
-/** Del the current record from the link ea buf */
-void mdd_links_del_buf(const struct lu_env *env, struct mdd_link_data *ldata,
- const struct lu_name *lname)
-{
- LASSERT(ldata->ml_leh != NULL);
-
- ldata->ml_leh->leh_reccount--;
- ldata->ml_leh->leh_len -= ldata->ml_reclen;
- memmove(ldata->ml_lee, (char *)ldata->ml_lee + ldata->ml_reclen,
- (char *)ldata->ml_leh + ldata->ml_leh->leh_len -
- (char *)ldata->ml_lee);
- CDEBUG(D_INODE, "Old link_ea name '%.*s' is removed\n",
- lname->ln_namelen, lname->ln_name);
-
-}
-
-/**
- * Check if such a link exists in linkEA.
- *
- * \param mdd_obj object being handled
- * \param pfid parent fid the link to be found for
- * \param lname name in the parent's directory entry pointing to this object
- * \param ldata link data the search to be done on
- *
- * \retval 0 success
- * \retval -ENOENT link does not exist
- * \retval -ve on error
- */
-int mdd_links_find(const struct lu_env *env, struct mdd_object *mdd_obj,
- struct mdd_link_data *ldata, const struct lu_name *lname,
- const struct lu_fid *pfid)
-{
- struct lu_name *tmpname = &mdd_env_info(env)->mti_name2;
- struct lu_fid *tmpfid = &mdd_env_info(env)->mti_fid;
- int count;
-
- LASSERT(ldata->ml_leh != NULL);
-
- /* link #0 */
- ldata->ml_lee = (struct link_ea_entry *)(ldata->ml_leh + 1);
-
- for (count = 0; count < ldata->ml_leh->leh_reccount; count++) {
- mdd_lee_unpack(ldata->ml_lee, &ldata->ml_reclen,
- tmpname, tmpfid);
- if (tmpname->ln_namelen == lname->ln_namelen &&
- lu_fid_eq(tmpfid, pfid) &&
- (strncmp(tmpname->ln_name, lname->ln_name,
- tmpname->ln_namelen) == 0))
- break;
- ldata->ml_lee = (struct link_ea_entry *)((char *)ldata->ml_lee +
- ldata->ml_reclen);
- }
-
- if (count == ldata->ml_leh->leh_reccount) {
- CDEBUG(D_INODE, "Old link_ea name '%.*s' not found\n",
- lname->ln_namelen, lname->ln_name);
- return -ENOENT;
- }
- return 0;
-}
-
-static int __mdd_links_add(const struct lu_env *env,
- struct mdd_object *mdd_obj,
- struct mdd_link_data *ldata,
- const struct lu_name *lname,
- const struct lu_fid *pfid,
- int first, int check)
-{
- int rc;
-
- if (ldata->ml_leh == NULL) {
- rc = first ? -ENODATA : mdd_links_read(env, mdd_obj, ldata);
- if (rc) {
- if (rc != -ENODATA)
- return rc;
- rc = mdd_links_new(env, ldata);
- if (rc)
- return rc;
- }
- }
-
- if (check) {
- rc = mdd_links_find(env, mdd_obj, ldata, lname, pfid);
- if (rc && rc != -ENOENT)
- return rc;
- if (rc == 0)
- return -EEXIST;
- }
-
- if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_LINKEA_MORE)) {
- struct lu_fid *tfid = &mdd_env_info(env)->mti_fid2;
-
- *tfid = *pfid;
- tfid->f_ver = ~0;
- mdd_links_add_buf(env, ldata, lname, tfid);
- }
-
- return mdd_links_add_buf(env, ldata, lname, pfid);
-}
-
-static int __mdd_links_del(const struct lu_env *env,
- struct mdd_object *mdd_obj,
- struct mdd_link_data *ldata,
- const struct lu_name *lname,
- const struct lu_fid *pfid)
-{
- int rc;
-
- if (ldata->ml_leh == NULL) {
- rc = mdd_links_read(env, mdd_obj, ldata);
- if (rc)
- return rc;
- }
-
- rc = mdd_links_find(env, mdd_obj, ldata, lname, pfid);
- if (rc)
- return rc;
-
- mdd_links_del_buf(env, ldata, lname);
- return 0;
-}
-
-int mdd_links_rename(const struct lu_env *env,
- struct mdd_object *mdd_obj,
- const struct lu_fid *oldpfid,
- const struct lu_name *oldlname,
- const struct lu_fid *newpfid,
- const struct lu_name *newlname,
- struct thandle *handle,
- int first, int check)
-{
- struct mdd_link_data ldata = { 0 };
- int updated = 0;
- int rc2 = 0;
- int rc = 0;
- ENTRY;
-
- if (OBD_FAIL_CHECK(OBD_FAIL_FID_IGIF))
- return 0;
-
- LASSERT(oldpfid != NULL || newpfid != NULL);
-
- if (mdd_obj->mod_flags & DEAD_OBJ)
- /* No more links, don't bother */
- RETURN(0);
-
- if (oldpfid != NULL) {
- rc = __mdd_links_del(env, mdd_obj, &ldata,
- oldlname, oldpfid);
- if (rc) {
- if ((check == 0) ||
- (rc != -ENODATA && rc != -ENOENT))
- GOTO(out, rc);
- /* No changes done. */
- rc = 0;
- } else {
- updated = 1;
- }
- }
-
- /* If renaming, add the new record */
- if (newpfid != NULL) {
- /* even if the add fails, we still delete the out-of-date
- * old link */
- rc2 = __mdd_links_add(env, mdd_obj, &ldata,
- newlname, newpfid, first, check);
- if (rc2 == -EEXIST)
- rc2 = 0;
- else if (rc2 == 0)
- updated = 1;
- }
-
- if (updated)
- rc = mdd_links_write(env, mdd_obj, &ldata, handle);
- EXIT;
-out:
- if (rc == 0)
- rc = rc2;
- if (rc) {
- int error = 1;
- if (rc == -EOVERFLOW || rc == - ENOENT)
- error = 0;
- if (oldpfid == NULL)
- CDEBUG(error ? D_ERROR : D_OTHER,
- "link_ea add '%.*s' failed %d "DFID"\n",
- newlname->ln_namelen, newlname->ln_name,
- rc, PFID(mdd_object_fid(mdd_obj)));
- else if (newpfid == NULL)
- CDEBUG(error ? D_ERROR : D_OTHER,
- "link_ea del '%.*s' failed %d "DFID"\n",
- oldlname->ln_namelen, oldlname->ln_name,
- rc, PFID(mdd_object_fid(mdd_obj)));
- else
- CDEBUG(error ? D_ERROR : D_OTHER,
- "link_ea rename '%.*s'->'%.*s' failed %d "
- DFID"\n",
- oldlname->ln_namelen, oldlname->ln_name,
- newlname->ln_namelen, newlname->ln_name,
- rc, PFID(mdd_object_fid(mdd_obj)));
- }
-
- if (ldata.ml_buf && ldata.ml_buf->lb_len > OBD_ALLOC_BIG)
- /* if we vmalloced a large buffer drop it */
- mdd_buf_put(ldata.ml_buf);
-
- return rc;
-}
-
-static inline int mdd_links_add(const struct lu_env *env,
- struct mdd_object *mdd_obj,
- const struct lu_fid *pfid,
- const struct lu_name *lname,
- struct thandle *handle, int first)
-{
- return mdd_links_rename(env, mdd_obj, NULL, NULL,
- pfid, lname, handle, first, 0);
-}
-
-static inline int mdd_links_del(const struct lu_env *env,
- struct mdd_object *mdd_obj,
- const struct lu_fid *pfid,
- const struct lu_name *lname,
- struct thandle *handle)
-{
- return mdd_links_rename(env, mdd_obj, pfid, lname,
- NULL, NULL, handle, 0, 0);
-}
-