-#ifdef HAVE_QUOTA_SUPPORT
- if (mds->mds_quota) {
- if (quota_popc)
- lquota_pending_commit(mds_quota_interface_ref, obd,
- qtpids, rec_pending, 1);
-
- if (quota_copc) {
- /* Trigger dqrel on the source owner of parent.
- * If failed, the next call for lquota_chkquota will
- * process it. */
- lquota_adjust(mds_quota_interface_ref, obd, 0, qspids, rc,
- FSFILT_OP_UNLINK_PARTIAL_PARENT);
-
- /* Trigger dqrel on the target owner of child.
- * If failed, the next call for lquota_chkquota
- * will process it. */
- lquota_adjust(mds_quota_interface_ref, obd, qtcids,
- qtpids, rc, quota_copc);
- }
- }
-#endif
- return rc;
-}
-
-/** enable/disable storing of hardlink info */
-int mdd_linkea_enable = 1;
-CFS_MODULE_PARM(mdd_linkea_enable, "d", int, 0644,
- "record hardlink info in EAs");
-
-/** 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 lu_buf *buf;
- struct lustre_capa *capa;
- struct link_ea_header *leh;
- int rc;
-
- /* First try a small buf */
- buf = mdd_buf_alloc(env, CFS_PAGE_SIZE);
- if (buf->lb_buf == NULL)
- return ERR_PTR(-ENOMEM);
-
- capa = mdd_object_capa(env, mdd_obj);
- rc = mdo_xattr_get(env, mdd_obj, buf, XATTR_NAME_LINK, capa);
- if (rc == -ERANGE) {
- /* Buf was too small, figure out what we need. */
- mdd_buf_put(buf);
- rc = mdo_xattr_get(env, mdd_obj, buf, XATTR_NAME_LINK, capa);
- if (rc < 0)
- return ERR_PTR(rc);
- buf = mdd_buf_alloc(env, rc);
- if (buf->lb_buf == NULL)
- return ERR_PTR(-ENOMEM);
- rc = mdo_xattr_get(env, mdd_obj, buf, XATTR_NAME_LINK, capa);
- }
- if (rc < 0)
- return ERR_PTR(rc);
-
- leh = 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 ERR_PTR(-EINVAL);
- if (leh->leh_reccount == 0)
- return ERR_PTR(-ENODATA);
-
- return buf;
-}
-
-/** 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);
- 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);
-}
-
-/** Add a record to the end of link ea buf */
-static int __mdd_links_add(const struct lu_env *env, struct lu_buf *buf,
- const struct lu_fid *pfid,
- const struct lu_name *lname)
-{
- struct link_ea_header *leh;
- struct link_ea_entry *lee;
- int reclen;
-
- if (lname == NULL || pfid == NULL)
- return -EINVAL;
-
- /* Make sure our buf is big enough for the new one */
- leh = buf->lb_buf;
- reclen = lname->ln_namelen + sizeof(struct link_ea_entry);
- if (leh->leh_len + reclen > buf->lb_len) {
- if (mdd_buf_grow(env, leh->leh_len + reclen) < 0)
- return -ENOMEM;
- }
-
- leh = buf->lb_buf;
- lee = buf->lb_buf + leh->leh_len;
- reclen = mdd_lee_pack(lee, lname, pfid);
- leh->leh_len += reclen;
- leh->leh_reccount++;
- return 0;
-}
-
-static 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;
-}
-
-/* For pathologic linkers, we don't want to spend lots of time scanning the
- * link ea. Limit ourseleves to something reasonable; links not in the EA
- * can be looked up via (slower) parent lookup.
- */
-#define LINKEA_MAX_COUNT 128
-
-static 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)
-{
- struct lu_buf *buf;
- struct link_ea_header *leh;
- int rc;
- ENTRY;
-
- if (!mdd_linkea_enable)
- RETURN(0);
-
- buf = first ? ERR_PTR(-ENODATA) : mdd_links_get(env, mdd_obj);
- if (IS_ERR(buf)) {
- rc = PTR_ERR(buf);
- if (rc != -ENODATA) {
- CERROR("link_ea read failed %d "DFID"\n", rc,
- PFID(mdd_object_fid(mdd_obj)));
- RETURN (rc);
- }
- /* empty EA; start one */
- buf = mdd_buf_alloc(env, CFS_PAGE_SIZE);
- if (buf->lb_buf == NULL)
- RETURN(-ENOMEM);
- leh = buf->lb_buf;
- leh->leh_magic = LINK_EA_MAGIC;
- leh->leh_len = sizeof(struct link_ea_header);
- leh->leh_reccount = 0;
- }
-
- leh = buf->lb_buf;
- if (leh->leh_reccount > LINKEA_MAX_COUNT)
- RETURN(-EOVERFLOW);
-
- rc = __mdd_links_add(env, buf, pfid, lname);
- if (rc)
- RETURN(rc);
-
- leh = buf->lb_buf;
- rc = __mdd_xattr_set(env, mdd_obj,
- mdd_buf_get_const(env, buf->lb_buf, leh->leh_len),
- XATTR_NAME_LINK, 0, handle);
- if (rc) {
- if (rc == -ENOSPC)
- CDEBUG(D_INODE, "link_ea add failed %d "DFID"\n", rc,
- PFID(mdd_object_fid(mdd_obj)));
- else
- CERROR("link_ea add failed %d "DFID"\n", rc,
- PFID(mdd_object_fid(mdd_obj)));
- }
-
- if (buf->lb_len > OBD_ALLOC_BIG)
- /* if we vmalloced a large buffer drop it */
- mdd_buf_put(buf);
-
- RETURN (rc);
-}
-
-static 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)
-{
- struct lu_buf *buf;
- struct link_ea_header *leh;
- struct link_ea_entry *lee;
- struct lu_name *tmpname = &mdd_env_info(env)->mti_name;
- struct lu_fid *tmpfid = &mdd_env_info(env)->mti_fid;
- int reclen = 0;
- int count;
- int rc, rc2 = 0;
- ENTRY;
-
- if (!mdd_linkea_enable)
- RETURN(0);
-
- if (mdd_obj->mod_flags & DEAD_OBJ)
- /* No more links, don't bother */
- RETURN(0);
-
- buf = mdd_links_get(env, mdd_obj);
- if (IS_ERR(buf)) {
- rc = PTR_ERR(buf);
- if (rc == -ENODATA)
- CDEBUG(D_INODE, "link_ea read failed %d "DFID"\n",
- rc, PFID(mdd_object_fid(mdd_obj)));
- else
- CERROR("link_ea read failed %d "DFID"\n",
- rc, PFID(mdd_object_fid(mdd_obj)));
- RETURN(rc);
- }
- leh = buf->lb_buf;
- lee = (struct link_ea_entry *)(leh + 1); /* link #0 */
-
- /* Find the old record */
- for(count = 0; count < leh->leh_reccount; count++) {
- mdd_lee_unpack(lee, &reclen, tmpname, tmpfid);
- if (tmpname->ln_namelen == oldlname->ln_namelen &&
- lu_fid_eq(tmpfid, oldpfid) &&
- (strncmp(tmpname->ln_name, oldlname->ln_name,
- tmpname->ln_namelen) == 0))
- break;
- lee = (struct link_ea_entry *)((char *)lee + reclen);
- }
- if ((count + 1) > leh->leh_reccount) {
- CDEBUG(D_INODE, "Old link_ea name '%.*s' not found\n",
- oldlname->ln_namelen, oldlname->ln_name);
- GOTO(out, rc = -ENOENT);
- }
-
- /* Remove the old record */
- leh->leh_reccount--;
- leh->leh_len -= reclen;
- memmove(lee, (char *)lee + reclen, (char *)leh + leh->leh_len -
- (char *)lee);
-
- /* If renaming, add the new record */
- if (newpfid != NULL) {
- /* if the add fails, we still delete the out-of-date old link */
- rc2 = __mdd_links_add(env, buf, newpfid, newlname);
- leh = buf->lb_buf;
- }
-
- rc = __mdd_xattr_set(env, mdd_obj,
- mdd_buf_get_const(env, buf->lb_buf, leh->leh_len),
- XATTR_NAME_LINK, 0, handle);
-
-out:
- if (rc == 0)
- rc = rc2;
- if (rc)
- CDEBUG(D_INODE, "link_ea mv/unlink '%.*s' failed %d "DFID"\n",
- oldlname->ln_namelen, oldlname->ln_name, rc,
- PFID(mdd_object_fid(mdd_obj)));
-
- if (buf->lb_len > OBD_ALLOC_BIG)
- /* if we vmalloced a large buffer drop it */
- mdd_buf_put(buf);
-
- RETURN (rc);