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,
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;
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;
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
/* 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,
**/
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);
}
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)
}
} 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);
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_lock(env, mdd_sobj, MOR_TGT_CHILD);
- /* Increase mod_count to add the source object to the orphan list,
- * so if other clients still send RPC to the old object, then these
- * objects can help the request to find the new object, see
- * mdt_reint_open() */
- mdd_sobj->mod_count++;
- rc = mdd_finish_unlink(env, mdd_sobj, ma, mdd_pobj, lname, handle);
- mdd_sobj->mod_count--;
+ 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);