* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2014, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
if (unlikely(mdd_is_dead_obj(mdd_obj)))
RETURN(-ESTALE);
+ if (!mdd_object_exists(mdd_obj))
+ RETURN(-ESTALE);
+
if (mdd_object_remote(mdd_obj)) {
CDEBUG(D_INFO, "%s: Object "DFID" locates on remote server\n",
mdd2obd_dev(m)->obd_name, PFID(mdo2fid(mdd_obj)));
- } else if (!mdd_object_exists(mdd_obj)) {
- RETURN(-ESTALE);
}
rc = mdd_permission_internal_locked(env, mdd_obj, pattr, mask,
RETURN(rc);
}
+/**
+ * Get parent FID of the directory
+ *
+ * Read parent FID from linkEA, if that fails, then do lookup
+ * dotdot to get the parent FID.
+ *
+ * \param[in] env execution environment
+ * \param[in] obj object from which to find the parent FID
+ * \param[in] attr attribute of the object
+ * \param[out] fid fid to get the parent FID
+ *
+ * \retval 0 if getting the parent FID succeeds.
+ * \retval negative errno if getting the parent FID fails.
+ **/
static inline int mdd_parent_fid(const struct lu_env *env,
struct mdd_object *obj,
const struct lu_attr *attr,
struct lu_fid *fid)
{
- return __mdd_lookup(env, &obj->mod_obj, attr, &lname_dotdot, fid, 0);
+ struct mdd_thread_info *info = mdd_env_info(env);
+ struct linkea_data ldata = { NULL };
+ struct lu_buf *buf = &info->mti_link_buf;
+ struct lu_name lname;
+ int rc = 0;
+
+ ENTRY;
+
+ LASSERT(S_ISDIR(mdd_object_type(obj)));
+
+ buf = lu_buf_check_and_alloc(buf, PATH_MAX);
+ if (buf->lb_buf == NULL)
+ GOTO(lookup, rc = 0);
+
+ ldata.ld_buf = buf;
+ rc = mdd_links_read(env, obj, &ldata);
+ if (rc != 0)
+ GOTO(lookup, rc);
+
+ LASSERT(ldata.ld_leh != NULL);
+ /* Directory should only have 1 parent */
+ if (ldata.ld_leh->leh_reccount > 1)
+ GOTO(lookup, rc);
+
+ ldata.ld_lee = (struct link_ea_entry *)(ldata.ld_leh + 1);
+
+ linkea_entry_unpack(ldata.ld_lee, &ldata.ld_reclen, &lname, fid);
+ if (likely(fid_is_sane(fid)))
+ RETURN(0);
+lookup:
+ rc = __mdd_lookup(env, &obj->mod_obj, attr, &lname_dotdot, fid, 0);
+ RETURN(rc);
}
/*
GOTO(out, rc = 0);
if (lu_fid_eq(pfid, lf))
GOTO(out, rc = 1);
- if (parent)
- mdd_object_put(env, parent);
+ if (parent != NULL)
+ mdd_object_put(env, parent);
parent = mdd_object_find(env, mdd, pfid);
- if (IS_ERR(parent)) {
+ if (IS_ERR(parent))
GOTO(out, rc = PTR_ERR(parent));
- } else if (mdd_object_remote(parent)) {
- /*FIXME: Because of the restriction of rename in Phase I.
- * If the parent is remote, we just assumed lf is not the
- * parent of P1 for now */
- GOTO(out, rc = 0);
- }
+
+ if (!mdd_object_exists(parent))
+ GOTO(out, rc = -EINVAL);
+
p1 = parent;
}
EXIT;
const struct lu_attr *pattr, struct mdd_object *cobj,
bool check_perm)
{
- struct mdd_thread_info *info = mdd_env_info(env);
- struct lu_buf *xbuf;
int rc = 0;
ENTRY;
if (mdd_is_dead_obj(pobj))
RETURN(-ENOENT);
- /* If the parent is a sub-stripe, check whether it is dead */
- xbuf = mdd_buf_get(env, info->mti_key, sizeof(info->mti_key));
- rc = mdo_xattr_get(env, pobj, xbuf, XATTR_NAME_LMV);
- if (unlikely(rc > 0)) {
- struct lmv_mds_md_v1 *lmv1 = xbuf->lb_buf;
-
- if (le32_to_cpu(lmv1->lmv_magic) == LMV_MAGIC_STRIPE &&
- le32_to_cpu(lmv1->lmv_hash_type) & LMV_HASH_FLAG_DEAD)
- RETURN(-ESTALE);
- }
- rc = 0;
-
if (check_perm)
rc = mdd_permission_internal_locked(env, pobj, pattr,
MAY_WRITE | MAY_EXEC,
* \param spfid - source parent fid
* \param tname - target name string
* \param sname - source name string
- * \param handle - transacion handle
+ * \param handle - transaction handle
*/
int mdd_changelog_ns_store(const struct lu_env *env,
struct mdd_device *mdd,
int error = 1;
if (rc == -EOVERFLOW || rc == -ENOSPC)
error = 0;
- if (oldpfid == NULL)
+ if (newlname == NULL)
+ CDEBUG(error ? D_ERROR : D_OTHER,
+ "link_ea add failed %d "DFID"\n",
+ rc, PFID(mdd_object_fid(mdd_obj)));
+ else 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)));
}
- if (ldata->ld_buf && ldata->ld_buf->lb_len > OBD_ALLOC_BIG)
+ if (is_vmalloc_addr(ldata->ld_buf))
/* if we vmalloced a large buffer drop it */
lu_buf_free(ldata->ld_buf);
int mdd_links_write(const struct lu_env *env, struct mdd_object *mdd_obj,
struct linkea_data *ldata, struct thandle *handle)
{
- const struct lu_buf *buf = mdd_buf_get_const(env, ldata->ld_buf->lb_buf,
- ldata->ld_leh->leh_len);
+ const struct lu_buf *buf;
int rc;
+ if (ldata == NULL || ldata->ld_buf == NULL ||
+ ldata->ld_leh == NULL)
+ return 0;
+
+ buf = mdd_buf_get_const(env, ldata->ld_buf->lb_buf,
+ ldata->ld_leh->leh_len);
if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_NO_LINKEA))
return 0;
stop:
mdd_trans_stop(env, mdd, rc, handle);
- if (ldata->ld_buf && ldata->ld_buf->lb_len > OBD_ALLOC_BIG)
+ if (is_vmalloc_addr(ldata->ld_buf))
/* if we vmalloced a large buffer drop it */
lu_buf_free(ldata->ld_buf);
out_pending:
return rc;
}
-static int mdd_mark_dead_object(const struct lu_env *env,
+static int mdd_mark_orphan_object(const struct lu_env *env,
struct mdd_object *obj, struct thandle *handle,
bool declare)
{
struct lu_attr *attr = MDD_ENV_VAR(env, la_for_start);
int rc;
- if (!declare)
- obj->mod_flags |= DEAD_OBJ;
-
if (!S_ISDIR(mdd_object_type(obj)))
return 0;
attr->la_valid = LA_FLAGS;
- attr->la_flags = LUSTRE_SLAVE_DEAD_FL;
+ attr->la_flags = LUSTRE_ORPHAN_FL;
if (declare)
rc = mdo_declare_attr_set(env, obj, attr, handle);
{
int rc;
- rc = mdd_mark_dead_object(env, obj, handle, true);
+ /* Sigh, we do not know if the unlink object will become orphan in
+ * declare phase, but fortunately the flags here does not matter
+ * in current declare implementation */
+ rc = mdd_mark_orphan_object(env, obj, handle, true);
if (rc != 0)
return rc;
- rc = orph_declare_index_insert(env, obj, mdd_object_type(obj), handle);
+ rc = mdo_declare_destroy(env, obj, handle);
if (rc != 0)
return rc;
- rc = mdo_declare_destroy(env, obj, handle);
+ rc = orph_declare_index_insert(env, obj, mdd_object_type(obj), handle);
if (rc != 0)
return rc;
struct thandle *th)
{
int rc = 0;
- int is_dir = S_ISDIR(ma->ma_attr.la_mode);
- ENTRY;
+ int is_dir = S_ISDIR(ma->ma_attr.la_mode);
+ ENTRY;
- LASSERT(mdd_write_locked(env, obj) != 0);
+ LASSERT(mdd_write_locked(env, obj) != 0);
if (ma->ma_attr.la_nlink == 0 || is_dir) {
- rc = mdd_mark_dead_object(env, obj, th, false);
- if (rc != 0)
- RETURN(rc);
-
- /* add new orphan and the object
- * will be deleted during mdd_close() */
- if (obj->mod_count) {
- rc = __mdd_orphan_add(env, obj, th);
- if (rc == 0)
- CDEBUG(D_HA, "Object "DFID" is inserted into "
- "orphan list, open count = %d\n",
- PFID(mdd_object_fid(obj)),
- obj->mod_count);
- else
- CERROR("Object "DFID" fail to be an orphan, "
- "open count = %d, maybe cause failed "
- "open replay\n",
- PFID(mdd_object_fid(obj)),
- obj->mod_count);
- } else {
+ /* add new orphan and the object
+ * will be deleted during mdd_close() */
+ obj->mod_flags |= DEAD_OBJ;
+ if (obj->mod_count) {
+ rc = __mdd_orphan_add(env, obj, th);
+ if (rc == 0)
+ CDEBUG(D_HA, "Object "DFID" is inserted into "
+ "orphan list, open count = %d\n",
+ PFID(mdd_object_fid(obj)),
+ obj->mod_count);
+ else
+ CERROR("Object "DFID" fail to be an orphan, "
+ "open count = %d, maybe cause failed "
+ "open replay\n",
+ PFID(mdd_object_fid(obj)),
+ obj->mod_count);
+
+ /* mark object as an orphan here, not
+ * before __mdd_orphan_add() as racing
+ * mdd_la_get() may propagate ORPHAN_OBJ
+ * causing the asserition */
+ rc = mdd_mark_orphan_object(env, obj, th, false);
+ } else {
rc = mdo_destroy(env, obj, th);
- }
+ }
} else if (!is_dir) {
/* old files may not have link ea; ignore errors */
mdd_links_del(env, obj, mdo2fid(pobj), lname, th);
rc = mdd_finish_unlink(env, mdd_cobj, ma, mdd_pobj, lname, handle);
/* fetch updated nlink */
- if (rc == 0)
- rc = mdd_la_get(env, mdd_cobj, cattr);
+ if (rc != 0)
+ GOTO(cleanup, rc);
+
+ rc = mdd_la_get(env, mdd_cobj, cattr);
+ /* if object is removed then we can't get its attrs,
+ * use last get */
+ if (rc == -ENOENT) {
+ cattr->la_nlink = 0;
+ rc = 0;
+ }
- /* if object is removed then we can't get its attrs, use last get */
if (cattr->la_nlink == 0) {
ma->ma_attr = *cattr;
ma->ma_valid |= MA_INODE;
}
+
EXIT;
cleanup:
if (likely(mdd_cobj != NULL))
int rc;
ENTRY;
- /* EEXIST check */
- if (mdd_is_dead_obj(obj))
- RETURN(-ENOENT);
+ /* EEXIST check */
+ if (mdd_is_dead_obj(obj))
+ RETURN(-ENOENT);
/*
* In some cases this lookup is not needed - we know before if name
RETURN(rc);
}
+static int mdd_index_delete(const struct lu_env *env,
+ struct mdd_object *mdd_pobj,
+ struct lu_attr *cattr,
+ const struct lu_name *lname)
+{
+ struct mdd_device *mdd = mdo2mdd(&mdd_pobj->mod_obj);
+ struct thandle *handle;
+ int rc;
+ ENTRY;
+
+ handle = mdd_trans_create(env, mdd);
+ if (IS_ERR(handle))
+ RETURN(PTR_ERR(handle));
+
+ rc = mdo_declare_index_delete(env, mdd_pobj, lname->ln_name,
+ handle);
+ if (rc != 0)
+ GOTO(stop, rc);
+
+ if (S_ISDIR(cattr->la_mode)) {
+ rc = mdo_declare_ref_del(env, mdd_pobj, handle);
+ if (rc != 0)
+ GOTO(stop, rc);
+ }
+
+ /* Since this will only be used in the error handler path,
+ * Let's set the thandle to be local and not mess the transno */
+ handle->th_local = 1;
+ rc = mdd_trans_start(env, mdd, handle);
+ if (rc)
+ GOTO(stop, rc);
+
+ rc = __mdd_index_delete(env, mdd_pobj, lname->ln_name,
+ S_ISDIR(cattr->la_mode), handle);
+ if (rc)
+ GOTO(stop, rc);
+stop:
+ mdd_trans_stop(env, mdd, rc, handle);
+ RETURN(rc);
+}
+
/*
* Create object and insert it into namespace.
*/
NULL, handle);
out_stop:
rc2 = mdd_trans_stop(env, mdd, rc, handle);
- if (rc == 0)
+ if (rc == 0) {
+ /* If creation fails, it is most likely due to the remote update
+ * failure, because local transaction will mostly succeed at
+ * this stage. There is no easy way to rollback all of previous
+ * updates, so let's remove the object from namespace, and
+ * LFSCK should handle the orphan object. */
+ if (rc2 < 0 && !mdd_object_remote(mdd_pobj))
+ mdd_index_delete(env, mdd_pobj, attr, lname);
rc = rc2;
+ }
out_free:
- if (ldata->ld_buf && ldata->ld_buf->lb_len > OBD_ALLOC_BIG)
+ if (is_vmalloc_addr(ldata->ld_buf))
/* if we vmalloced a large buffer drop it */
lu_buf_free(ldata->ld_buf);
if (rc != 0)
return rc;
- /* name from target dir (old name), we declare it unconditionally
- * as mdd_rename() calls delete unconditionally as well. so just
- * to balance declarations vs calls to change ... */
- rc = mdo_declare_index_delete(env, mdd_tpobj, tname->ln_name, handle);
- if (rc)
- return rc;
-
if (mdd_tobj && mdd_object_exists(mdd_tobj)) {
/* delete target child in target parent directory */
+ rc = mdo_declare_index_delete(env, mdd_tpobj, tname->ln_name,
+ handle);
+ if (rc)
+ return rc;
+
rc = mdo_declare_ref_del(env, mdd_tobj, handle);
if (rc)
return rc;
mdd_tobj = md2mdd_obj(tobj);
mdd_sobj = mdd_object_find(env, mdd, lf);
+ if (IS_ERR(mdd_sobj))
+ RETURN(PTR_ERR(mdd_sobj));
rc = mdd_la_get(env, mdd_sobj, cattr);
if (rc)
if (rc < 0)
GOTO(out_pending, rc);
+ /* FIXME: Should consider tobj and sobj too in rename_lock. */
+ rc = mdd_rename_order(env, mdd, mdd_spobj, pattr, mdd_tpobj);
+ if (rc < 0)
+ GOTO(out_pending, rc);
+
handle = mdd_trans_create(env, mdd);
if (IS_ERR(handle))
GOTO(out_pending, rc = PTR_ERR(handle));
memset(ldata, 0, sizeof(*ldata));
- mdd_linkea_prepare(env, mdd_sobj, NULL, NULL, mdd_object_fid(mdd_tpobj),
- ltname, 1, 0, ldata);
+ mdd_linkea_prepare(env, mdd_sobj, mdd_object_fid(mdd_spobj), lsname,
+ mdd_object_fid(mdd_tpobj), ltname, 1, 0, ldata);
rc = mdd_declare_rename(env, mdd, mdd_spobj, mdd_tpobj, mdd_sobj,
mdd_tobj, lsname, ltname, ma, ldata, handle);
if (rc)
if (rc)
GOTO(stop, rc);
- /* FIXME: Should consider tobj and sobj too in rename_lock. */
- rc = mdd_rename_order(env, mdd, mdd_spobj, pattr, mdd_tpobj);
- if (rc < 0)
- GOTO(cleanup_unlocked, rc);
-
is_dir = S_ISDIR(cattr->la_mode);
- /* Remove source name from source directory */
+ /* Remove source name from source directory */
rc = __mdd_index_delete(env, mdd_spobj, sname, is_dir, handle);
- if (rc)
- GOTO(cleanup, rc);
+ if (rc != 0)
+ GOTO(stop, rc);
- /* "mv dir1 dir2" needs "dir1/.." link update */
- if (is_dir && mdd_sobj && !lu_fid_eq(spobj_fid, tpobj_fid)) {
+ /* "mv dir1 dir2" needs "dir1/.." link update */
+ if (is_dir && !lu_fid_eq(spobj_fid, tpobj_fid)) {
rc = __mdd_index_delete_only(env, mdd_sobj, dotdot, handle);
if (rc != 0)
GOTO(fixup_spobj2, rc);
GOTO(fixup_spobj, rc);
}
- /* Remove target name from target directory
- * Here tobj can be remote one, so we do index_delete unconditionally
- * and -ENOENT is allowed.
- */
- rc = __mdd_index_delete(env, mdd_tpobj, tname, is_dir, handle);
- if (rc != 0) {
- if (mdd_tobj) {
- /* tname might been renamed to something else */
- GOTO(fixup_spobj, rc);
- }
- if (rc != -ENOENT)
- GOTO(fixup_spobj, rc);
- }
+ if (mdd_tobj != NULL && mdd_object_exists(mdd_tobj)) {
+ rc = __mdd_index_delete(env, mdd_tpobj, tname, is_dir, handle);
+ if (rc != 0)
+ /* tname might been renamed to something else */
+ GOTO(fixup_spobj, rc);
+ }
/* Insert new fid with target name into target dir */
rc = __mdd_index_insert(env, mdd_tpobj, lf, cattr->la_mode,
LASSERT(ma->ma_attr.la_valid & LA_CTIME);
la->la_ctime = la->la_mtime = ma->ma_attr.la_ctime;
- /* XXX: mdd_sobj must be local one if it is NOT NULL. */
- if (mdd_sobj) {
- la->la_valid = LA_CTIME;
- rc = mdd_update_time(env, mdd_sobj, cattr, la, handle);
- if (rc)
- GOTO(fixup_tpobj, rc);
- }
+ /* XXX: mdd_sobj must be local one if it is NOT NULL. */
+ la->la_valid = LA_CTIME;
+ rc = mdd_update_time(env, mdd_sobj, cattr, la, handle);
+ if (rc)
+ GOTO(fixup_tpobj, rc);
+
+ /* Update the linkEA for the source object */
+ mdd_write_lock(env, mdd_sobj, MOR_SRC_CHILD);
+ rc = mdd_links_rename(env, mdd_sobj, mdo2fid(mdd_spobj), lsname,
+ mdo2fid(mdd_tpobj), ltname, handle, ldata,
+ 0, 0);
+ if (rc == -ENOENT)
+ /* Old files might not have EA entry */
+ mdd_links_add(env, mdd_sobj, mdo2fid(mdd_spobj),
+ lsname, handle, NULL, 0);
+ mdd_write_unlock(env, mdd_sobj);
+ /* We don't fail the transaction if the link ea can't be
+ updated -- fid2path will use alternate lookup method. */
+ rc = 0;
/* Remove old target object
* For tobj is remote case cmm layer has processed
/* fetch updated nlink */
rc = mdd_la_get(env, mdd_tobj, tattr);
- if (rc != 0) {
+ if (rc == -ENOENT) {
+ /* the object got removed, let's
+ * return the latest known attributes */
+ tattr->la_nlink = 0;
+ rc = 0;
+ } else if (rc != 0) {
CERROR("%s: Failed to get nlink for tobj "
DFID": rc = %d\n",
mdd2obd_dev(mdd)->obd_name,
if (mdd_spobj != mdd_tpobj) {
la->la_valid = LA_CTIME | LA_MTIME;
rc = mdd_update_time(env, mdd_tpobj, tpattr, la, handle);
+ if (rc != 0)
+ GOTO(fixup_tpobj, rc);
}
- if (rc == 0 && mdd_sobj) {
- mdd_write_lock(env, mdd_sobj, MOR_SRC_CHILD);
- rc = mdd_links_rename(env, mdd_sobj, mdo2fid(mdd_spobj), lsname,
- mdo2fid(mdd_tpobj), ltname, handle, NULL,
- 0, 0);
- if (rc == -ENOENT)
- /* Old files might not have EA entry */
- mdd_links_add(env, mdd_sobj, mdo2fid(mdd_spobj),
- lsname, handle, NULL, 0);
- mdd_write_unlock(env, mdd_sobj);
- /* We don't fail the transaction if the link ea can't be
- updated -- fid2path will use alternate lookup method. */
- rc = 0;
- }
-
EXIT;
fixup_tpobj:
if (tobj_locked)
mdd_write_unlock(env, mdd_tobj);
-cleanup_unlocked:
if (rc == 0)
rc = mdd_changelog_ns_store(env, mdd, CL_RENAME, cl_flags,
mdd_tobj, tpobj_fid, lf, spobj_fid,
**/
static int mdd_linkea_update_child_internal(const struct lu_env *env,
struct mdd_object *parent,
+ struct mdd_object *newparent,
struct mdd_object *child,
const char *name, int namelen,
struct thandle *handle,
&lname, &fid);
if (strncmp(lname.ln_name, name, namelen) != 0 ||
- lu_fid_eq(&fid, mdd_object_fid(parent))) {
+ !lu_fid_eq(&fid, mdd_object_fid(parent))) {
ldata.ld_lee = (struct link_ea_entry *)
((char *)ldata.ld_lee +
ldata.ld_reclen);
CDEBUG(D_INFO, "%s: update "DFID" with %.*s:"DFID"\n",
mdd2obd_dev(mdd)->obd_name, PFID(mdd_object_fid(child)),
lname.ln_namelen, lname.ln_name,
- PFID(mdd_object_fid(parent)));
+ PFID(mdd_object_fid(newparent)));
/* update to the new parent fid */
linkea_entry_pack(ldata.ld_lee, &lname,
- mdd_object_fid(parent));
+ mdd_object_fid(newparent));
if (declare)
rc = mdd_declare_links_add(env, child, handle, &ldata,
MLAO_IGNORE);
static int mdd_linkea_declare_update_child(const struct lu_env *env,
struct mdd_object *parent,
+ struct mdd_object *newparent,
struct mdd_object *child,
const char *name, int namelen,
struct thandle *handle)
{
- return mdd_linkea_update_child_internal(env, parent, child, name,
+ return mdd_linkea_update_child_internal(env, parent, newparent,
+ child, name,
namelen, handle, true);
}
static int mdd_linkea_update_child(const struct lu_env *env,
struct mdd_object *parent,
+ struct mdd_object *newparent,
struct mdd_object *child,
const char *name, int namelen,
struct thandle *handle)
{
- return mdd_linkea_update_child_internal(env, parent, child, name,
+ return mdd_linkea_update_child_internal(env, parent, newparent,
+ child, name,
namelen, handle, false);
}
struct mdd_object *mdd_sobj,
struct mdd_object *mdd_tobj,
const struct lu_name *child_name,
+ struct linkea_data *ldata,
struct thandle *handle,
int declare)
{
struct mdd_thread_info *info = mdd_env_info(env);
- struct linkea_data *ldata = &info->mti_link_data;
int count;
int rc = 0;
ENTRY;
- rc = mdd_links_read(env, mdd_sobj, ldata);
- if (rc != 0) {
- if (rc == -ENOENT || rc == -ENODATA)
- rc = 0;
- RETURN(rc);
- }
+ LASSERT(ldata->ld_buf != NULL);
+again:
/* If it is mulitple links file, we need update the name entry for
* all parent */
LASSERT(ldata->ld_leh != NULL);
linkea_entry_unpack(ldata->ld_lee, &ldata->ld_reclen,
&lname, &fid);
- ldata->ld_lee = (struct link_ea_entry *)((char *)ldata->ld_lee +
- ldata->ld_reclen);
pobj = mdd_object_find(env, mdd, &fid);
if (IS_ERR(pobj)) {
CWARN("%s: cannot find obj "DFID": rc = %ld\n",
mdd2obd_dev(mdd)->obd_name, PFID(&fid),
PTR_ERR(pobj));
- continue;
+ linkea_del_buf(ldata, &lname);
+ goto again;
}
if (!mdd_object_exists(pobj)) {
CDEBUG(D_INFO, "%s: obj "DFID" does not exist\n",
mdd2obd_dev(mdd)->obd_name, PFID(&fid));
- GOTO(next_put, rc);
+ linkea_del_buf(ldata, &lname);
+ mdd_object_put(env, pobj);
+ goto again;
}
if (pobj == mdd_pobj &&
CDEBUG(D_INFO, "%s: skip its own %s: "DFID"\n",
mdd2obd_dev(mdd)->obd_name, child_name->ln_name,
PFID(&fid));
- GOTO(next_put, rc);
+ linkea_del_buf(ldata, &lname);
+ mdd_object_put(env, pobj);
+ goto again;
}
CDEBUG(D_INFO, "%s: update "DFID" with "DNAME":"DFID"\n",
if (rc)
GOTO(next_put, rc);
} else {
- rc = __mdd_index_delete(env, pobj, lname.ln_name,
- 0, handle);
- if (rc)
+ char *tmp_name = info->mti_key;
+
+ if (lname.ln_namelen >= sizeof(info->mti_key)) {
+ /* lnamelen is too big(> NAME_MAX + 16),
+ * something wrong about this linkea, let's
+ * skip it */
+ linkea_del_buf(ldata, &lname);
+ mdd_object_put(env, pobj);
+ goto again;
+ }
+
+ /* Note: lname might be without \0 at the end, see
+ * linkea_entry_unpack(), let's add extra \0 by
+ * snprintf */
+ snprintf(tmp_name, sizeof(info->mti_key), "%.*s",
+ lname.ln_namelen, lname.ln_name);
+ lname.ln_name = tmp_name;
+
+ /* Let's check if this linkEA still valid, before
+ * it might be packed into the RPC buffer. */
+ rc = mdd_lookup(env, &pobj->mod_obj, &lname,
+ &info->mti_fid, NULL);
+ if (rc < 0 ||
+ !lu_fid_eq(&info->mti_fid,
+ mdd_object_fid(mdd_sobj))) {
+ /* skip invalid linkea entry */
+ linkea_del_buf(ldata, &lname);
+ mdd_object_put(env, pobj);
+ goto again;
+ }
+
+ rc = __mdd_index_delete(env, pobj, tmp_name, 0, handle);
+ if (rc != 0)
GOTO(next_put, rc);
rc = __mdd_index_insert(env, pobj,
mdd_object_fid(mdd_tobj),
mdd_object_type(mdd_tobj),
- lname.ln_name, handle);
+ tmp_name, handle);
if (rc != 0)
GOTO(next_put, rc);
mdd_object_put(env, pobj);
if (rc != 0)
break;
+
+ ldata->ld_lee = (struct link_ea_entry *)((char *)ldata->ld_lee +
+ ldata->ld_reclen);
}
RETURN(rc);
int list_xsize;
struct lu_buf list_xbuf;
int rc;
+ int rc1;
/* retrieve xattr list from the old object */
list_xsize = mdo_xattr_list(env, mdd_sobj, &LU_BUF_NULL);
if (rc != 0)
GOTO(stop_trans, rc);
stop_trans:
- mdd_trans_stop(env, mdd, rc, handle);
+ rc1 = mdd_trans_stop(env, mdd, rc, handle);
+ if (rc == 0)
+ rc = rc1;
if (rc != 0)
GOTO(out, rc);
next:
buf, 0, handle);
if (rc != 0)
return rc;
- } else if (S_ISDIR(la->la_mode)) {
+ } else if (S_ISDIR(la->la_mode) && ldata != NULL) {
rc = mdd_declare_links_add(env, mdd_tobj, handle, ldata,
MLAO_IGNORE);
if (rc != 0)
RETURN(rc);
}
spec->u.sp_symname = link_buf.lb_buf;
- } else if S_ISREG(la->la_mode) {
+ } else if (S_ISREG(la->la_mode)) {
/* retrieve lov of the old object */
rc = mdd_get_lov_ea(env, mdd_sobj, &lmm_buf);
if (rc != 0 && rc != -ENODATA)
}
} else if (S_ISDIR(la->la_mode)) {
rc = mdd_links_read(env, mdd_sobj, ldata);
- if (rc < 0 && rc != -ENODATA)
+ if (rc == -ENODATA) {
+ /* ignore the non-linkEA error */
+ ldata = NULL;
+ rc = 0;
+ }
+ if (rc < 0)
RETURN(rc);
}
if (rc != 0)
GOTO(stop_trans, rc);
+ /* don't set nlink from the original object */
+ la->la_valid &= ~LA_NLINK;
+
/* create the target object */
rc = mdd_object_create(env, mdd_pobj, mdd_tobj, la, spec, NULL, NULL,
hint, handle);
if (rc != 0)
GOTO(stop_trans, rc);
- if (S_ISDIR(la->la_mode)) {
+ if (S_ISDIR(la->la_mode) && ldata != NULL) {
rc = mdd_links_write(env, mdd_tobj, ldata, handle);
if (rc != 0)
GOTO(stop_trans, rc);
la_flag->la_flags = la->la_flags | LUSTRE_IMMUTABLE_FL;
rc = mdo_attr_set(env, mdd_sobj, la_flag, handle);
stop_trans:
- if (handle != NULL)
- mdd_trans_stop(env, mdd, rc, handle);
+ if (handle != NULL) {
+ int rc1;
+
+ rc1 = mdd_trans_stop(env, mdd, rc, handle);
+ if (rc == 0)
+ rc = rc1;
+ }
out_free:
if (lmm_buf.lb_buf != NULL)
OBD_FREE(lmm_buf.lb_buf, lmm_buf.lb_len);
int recsize;
int is_dir;
bool target_exist = false;
+ int rc1;
len = iops->key_size(env, it);
if (len == 0)
if (IS_ERR(child))
GOTO(out, rc = PTR_ERR(child));
+ mdd_write_lock(env, child, MOR_SRC_CHILD);
is_dir = S_ISDIR(mdd_object_type(child));
snprintf(name, ent->lde_namelen + 1, "%s", ent->lde_name);
handle = mdd_trans_create(env, mdd);
if (IS_ERR(handle))
- GOTO(out, rc = PTR_ERR(handle));
+ GOTO(out_put, rc = PTR_ERR(handle));
/* Note: this transaction is part of migration, and it is not
* the last step of migration, so we set th_local = 1 to avoid
GOTO(out_put, rc);
}
- rc = mdd_linkea_declare_update_child(env, mdd_tobj,
+ rc = mdd_linkea_declare_update_child(env, mdd_sobj,mdd_tobj,
child, name,
strlen(name),
handle);
GOTO(out_put, rc);
}
- rc = mdd_linkea_update_child(env, mdd_tobj, child, name,
+ rc = mdd_linkea_update_child(env, mdd_sobj, mdd_tobj,
+ child, name,
strlen(name), handle);
out_put:
+ mdd_write_unlock(env, child);
mdd_object_put(env, child);
- mdd_trans_stop(env, mdd, rc, handle);
+ rc1 = mdd_trans_stop(env, mdd, rc, handle);
+ if (rc == 0)
+ rc = rc1;
+
if (rc != 0)
GOTO(out, rc);
next:
struct mdd_object *mdd_pobj,
struct mdd_object *mdd_sobj,
struct mdd_object *mdd_tobj,
- struct thandle *handle,
- const struct lu_name *child_name)
+ const struct lu_name *child_name,
+ struct linkea_data *ldata,
+ struct thandle *handle)
{
return mdd_update_linkea_internal(env, mdd_pobj, mdd_sobj, mdd_tobj,
- child_name, handle, 1);
+ child_name, ldata, handle, 1);
}
static int mdd_update_linkea(const struct lu_env *env,
struct mdd_object *mdd_pobj,
struct mdd_object *mdd_sobj,
struct mdd_object *mdd_tobj,
- struct thandle *handle,
- const struct lu_name *child_name)
+ const struct lu_name *child_name,
+ struct linkea_data *ldata,
+ struct thandle *handle)
{
return mdd_update_linkea_internal(env, mdd_pobj, mdd_sobj, mdd_tobj,
- child_name, handle, 0);
+ child_name, ldata, handle, 0);
}
static int mdd_declare_migrate_update_name(const struct lu_env *env,
const struct lu_name *lname,
struct lu_attr *la,
struct lu_attr *parent_la,
+ struct linkea_data *ldata,
struct thandle *handle)
{
- struct lu_attr *la_flag = MDD_ENV_VAR(env, tattr);
- int rc;
+ struct mdd_device *mdd = mdo2mdd(&mdd_sobj->mod_obj);
+ struct lu_attr *la_flag = MDD_ENV_VAR(env, tattr);
+ int rc;
/* Revert IMMUTABLE flag */
la_flag->la_valid = LA_FLAGS;
if (rc != 0)
return rc;
- rc = mdd_declare_update_linkea(env, mdd_pobj, mdd_sobj,
- mdd_tobj, handle, lname);
- if (rc != 0)
- return rc;
+ if (ldata->ld_buf != NULL) {
+ rc = mdd_declare_update_linkea(env, mdd_pobj, mdd_sobj,
+ mdd_tobj, lname, ldata, handle);
+ if (rc != 0)
+ return rc;
+ }
if (S_ISREG(mdd_object_type(mdd_sobj))) {
rc = mdo_declare_xattr_del(env, mdd_sobj, XATTR_NAME_LOV,
handle);
if (rc != 0)
return rc;
+
+ handle->th_complex = 1;
+ rc = mdo_declare_xattr_set(env, mdd_tobj, NULL,
+ XATTR_NAME_FID,
+ LU_XATTR_REPLACE, handle);
+ if (rc < 0)
+ return rc;
}
if (S_ISDIR(mdd_object_type(mdd_sobj))) {
return rc;
rc = mdo_declare_attr_set(env, mdd_pobj, parent_la, handle);
+ if (rc != 0)
+ return rc;
+
+ rc = mdd_declare_changelog_store(env, mdd, lname, NULL, handle);
return rc;
}
struct lu_attr *so_attr = MDD_ENV_VAR(env, cattr);
struct lu_attr *la_flag = MDD_ENV_VAR(env, tattr);
struct mdd_device *mdd = mdo2mdd(&mdd_sobj->mod_obj);
+ struct linkea_data *ldata = &mdd_env_info(env)->mti_link_data;
struct thandle *handle;
int is_dir = S_ISDIR(mdd_object_type(mdd_sobj));
const char *name = lname->ln_name;
if (rc != 0)
RETURN(rc);
+ ldata->ld_buf = NULL;
+ rc = mdd_links_read(env, mdd_sobj, ldata);
+ if (rc != 0 && rc != -ENOENT && rc != -ENODATA)
+ RETURN(rc);
+
handle = mdd_trans_create(env, mdd);
if (IS_ERR(handle))
RETURN(PTR_ERR(handle));
rc = mdd_declare_migrate_update_name(env, mdd_pobj, mdd_sobj, mdd_tobj,
- lname, so_attr, p_la, handle);
+ lname, so_attr, p_la, ldata,
+ handle);
if (rc != 0) {
/* If the migration can not be fit in one transaction, just
* leave it in the original MDT */
if (rc != 0)
GOTO(stop_trans, rc);
- rc = mdd_update_linkea(env, mdd_pobj, mdd_sobj, mdd_tobj,
- handle, lname);
- if (rc != 0)
- GOTO(stop_trans, rc);
+ if (ldata->ld_buf != NULL) {
+ rc = mdd_update_linkea(env, mdd_pobj, mdd_sobj, mdd_tobj,
+ lname, ldata, handle);
+ if (rc != 0)
+ GOTO(stop_trans, rc);
+
+ /* linkea update might decrease the source object
+ * nlink, let's get the attr again after ref_del */
+ rc = mdd_la_get(env, mdd_sobj, so_attr);
+ if (rc != 0)
+ GOTO(stop_trans, rc);
+ }
if (S_ISREG(so_attr->la_mode)) {
if (so_attr->la_nlink == 1) {
handle);
if (rc != 0 && rc != -ENODATA)
GOTO(stop_trans, rc);
+
+ rc = mdo_xattr_set(env, mdd_tobj, NULL,
+ XATTR_NAME_FID,
+ LU_XATTR_REPLACE, handle);
+ if (rc < 0)
+ GOTO(stop_trans, rc);
}
}
if (rc != 0)
GOTO(stop_trans, rc);
+ linkea_add_buf(ldata, lname, mdd_object_fid(mdd_pobj));
rc = mdd_links_add(env, mdd_tobj, mdo2fid(mdd_pobj), lname, handle,
- NULL, 1);
+ ldata, 1);
if (rc != 0)
GOTO(stop_trans, rc);
- mdd_write_lock(env, mdd_sobj, MOR_SRC_CHILD);
+ mdd_write_lock(env, mdd_sobj, MOR_TGT_CHILD);
+
+ mdd_sobj->mod_flags |= DEAD_OBJ;
+ rc = mdd_mark_orphan_object(env, mdd_sobj, handle, false);
+ if (rc != 0)
+ GOTO(out_unlock, rc);
+
+ rc = __mdd_orphan_add(env, mdd_sobj, handle);
+ if (rc != 0)
+ GOTO(out_unlock, rc);
+
mdo_ref_del(env, mdd_sobj, handle);
if (is_dir)
mdo_ref_del(env, mdd_sobj, handle);
ma->ma_attr = *so_attr;
ma->ma_valid |= MA_INODE;
- rc = mdd_finish_unlink(env, mdd_sobj, ma, mdd_pobj, lname, handle);
- if (rc != 0)
- GOTO(out_unlock, rc);
rc = mdd_attr_set_internal(env, mdd_pobj, p_la, handle, 0);
if (rc != 0)
GOTO(out_unlock, rc);
+ rc = mdd_changelog_ns_store(env, mdd, CL_MIGRATE, 0, mdd_tobj,
+ mdo2fid(mdd_pobj), mdo2fid(mdd_sobj),
+ mdo2fid(mdd_pobj), lname, lname, handle);
+ if (rc != 0) {
+ CWARN("%s: changelog for migrate %s "DFID
+ "under "DFID" failed: rc = %d\n",
+ mdd2obd_dev(mdd)->obd_name, lname->ln_name,
+ PFID(mdd_object_fid(mdd_sobj)),
+ PFID(mdd_object_fid(mdd_pobj)), rc);
+ /* Sigh, there are no easy way to migrate back the object, so
+ * let's reset the result to 0 for now XXX */
+ rc = 0;
+ }
out_unlock:
mdd_write_unlock(env, mdd_sobj);
RETURN(rc);
}
+static int mdd_fld_lookup(const struct lu_env *env, struct mdd_device *mdd,
+ const struct lu_fid *fid, __u32 *mdt_index)
+{
+ struct lu_seq_range *range = &mdd_env_info(env)->mti_range;
+ struct seq_server_site *ss;
+ int rc;
+
+ ss = mdd->mdd_md_dev.md_lu_dev.ld_site->ld_seq_site;
+
+ range->lsr_flags = LU_SEQ_RANGE_MDT;
+ rc = fld_server_lookup(env, ss->ss_server_fld, fid->f_seq, range);
+ if (rc != 0)
+ return rc;
+
+ *mdt_index = range->lsr_index;
+
+ return 0;
+}
/**
* Check whether we should migrate the file/dir
* return val
{
struct mdd_thread_info *info = mdd_env_info(env);
struct linkea_data *ldata = &info->mti_link_data;
+ struct mdd_device *mdd = mdo2mdd(&pobj->mod_obj);
int mgr_easize;
struct lu_buf *mgr_buf;
int count;
int rc;
-
+ __u64 mdt_index;
ENTRY;
mgr_easize = lmv_mds_md_size(2, LMV_MAGIC_V1);
if (rc != 0) {
/* For multiple links files, if there are no linkEA data at all,
* means the file might be created before linkEA is enabled, and
- * all all of its links should not be migrated yet, otherwise
- * it should have some linkEA there */
+ * all of its links should not be migrated yet, otherwise it
+ * should have some linkEA there */
if (rc == -ENOENT || rc == -ENODATA)
RETURN(1);
RETURN(rc);
}
- /* If it is mulitple links file, we need update the name entry for
- * all parent */
+ mdt_index = mdd->mdd_md_dev.md_lu_dev.ld_site->ld_seq_site->ss_node_id;
+ /* If there are still links locally, then the file will not be
+ * migrated. */
LASSERT(ldata->ld_leh != NULL);
ldata->ld_lee = (struct link_ea_entry *)(ldata->ld_leh + 1);
for (count = 0; count < ldata->ld_leh->leh_reccount; count++) {
- struct mdd_device *mdd = mdo2mdd(&sobj->mod_obj);
- struct mdd_object *lpobj;
struct lu_name lname;
struct lu_fid fid;
+ __u32 parent_mdt_index;
linkea_entry_unpack(ldata->ld_lee, &ldata->ld_reclen,
&lname, &fid);
ldata->ld_lee = (struct link_ea_entry *)((char *)ldata->ld_lee +
ldata->ld_reclen);
- lpobj = mdd_object_find(env, mdd, &fid);
- if (IS_ERR(lpobj)) {
- CWARN("%s: cannot find obj "DFID": rc = %ld\n",
- mdd2obd_dev(mdd)->obd_name, PFID(&fid),
- PTR_ERR(lpobj));
- continue;
- }
- if (!mdd_object_exists(lpobj) || mdd_object_remote(lpobj)) {
- CDEBUG(D_INFO, DFID"%.*s: is on remote MDT.\n",
- PFID(&fid), lname.ln_namelen, lname.ln_name);
- mdd_object_put(env, lpobj);
+ rc = mdd_fld_lookup(env, mdd, &fid, &parent_mdt_index);
+ if (rc != 0)
+ RETURN(rc);
+
+ /* Migrate the object only if none of its parents are on the
+ * current MDT. */
+ if (parent_mdt_index != mdt_index)
continue;
- }
CDEBUG(D_INFO, DFID"still has local entry %.*s "DFID"\n",
PFID(mdd_object_fid(sobj)), lname.ln_namelen,
lname.ln_name, PFID(&fid));
- mdd_object_put(env, lpobj);
rc = 1;
break;
}
struct mdd_object *mdd_pobj = md2mdd_obj(pobj);
struct mdd_device *mdd = mdo2mdd(pobj);
struct mdd_object *mdd_sobj = md2mdd_obj(sobj);
- struct mdd_object *mdd_tobj = NULL;
+ struct mdd_object *mdd_tobj = md2mdd_obj(tobj);
struct lu_attr *so_attr = MDD_ENV_VAR(env, cattr);
struct lu_attr *pattr = MDD_ENV_VAR(env, pattr);
int rc;
/* If the file will being migrated, it will check whether
* the file is being opened by someone else right now */
mdd_read_lock(env, mdd_sobj, MOR_SRC_CHILD);
- if (mdd_sobj->mod_count >= 1) {
+ if (mdd_sobj->mod_count > 0) {
CERROR("%s: "DFID"%s is already opened count %d: rc = %d\n",
mdd2obd_dev(mdd)->obd_name,
PFID(mdd_object_fid(mdd_sobj)), lname->ln_name,
/* step 1: Check whether the orphan object has been created, and create
* orphan object on the remote MDT if needed */
- mdd_tobj = md2mdd_obj(tobj);
if (!mdd_object_exists(mdd_tobj)) {
rc = mdd_migrate_create(env, mdd_pobj, mdd_sobj, mdd_tobj,
lname, so_attr);
GOTO(put, rc);
}
+ LASSERT(mdd_object_exists(mdd_tobj));
/* step 2: migrate xattr */
rc = mdd_migrate_xattrs(env, mdd_sobj, mdd_tobj);
if (rc != 0)
OBD_FAIL_TIMEOUT(OBD_FAIL_MIGRATE_DELAY, cfs_fail_val);
}
+ LASSERT(mdd_object_exists(mdd_tobj));
/* step 4: update name entry to the new object */
rc = mdd_migrate_update_name(env, mdd_pobj, mdd_sobj, mdd_tobj, lname,
ma);