if (rc > 0 && mdt_lmm_is_flr(info->mti_big_lmm))
GOTO(out_put, rc = -EOPNOTSUPP);
}
+
+ /* For truncate, the file size sent from client
+ * is believable, but the blocks are incorrect,
+ * which makes the block size in LSOM attribute
+ * inconsisent with the real block size.
+ */
+ rc = mdt_lsom_update(info, mo, true);
+ if (rc)
+ GOTO(out_put, rc);
}
if ((ma->ma_valid & MA_INODE) && ma->ma_attr.la_valid) {
struct mdt_lock_handle *child_lh;
struct ldlm_enqueue_info *einfo = &info->mti_einfo;
__u64 lock_ibits;
- bool cos_incompat = false;
+ bool cos_incompat = false, discard = false;
int no_name = 0;
int rc;
if (rc)
GOTO(out_stat, rc);
} else {
- mdt_dom_check_and_discard(info, mc);
+ discard = true;
}
mdt_handle_last_unlink(info, mc, ma);
unlock_child:
mdt_reint_striped_unlock(info, mc, child_lh, einfo, rc);
put_child:
+ if (discard)
+ mdt_dom_check_and_discard(info, mc);
mdt_object_put(info->mti_env, mc);
unlock_parent:
mdt_object_unlock(info, mp, parent_lh, rc);
EXIT;
}
-/*
- * This is is_subdir() variant, it is CMD if cmm forwards it to correct
- * target. Source should not be ancestor of target dir. May be other rename
- * checks can be moved here later.
- */
-static int mdt_is_subdir(struct mdt_thread_info *info,
- struct mdt_object *dir,
- const struct lu_fid *fid)
-{
- struct lu_fid dir_fid = dir->mot_header.loh_fid;
- int rc = 0;
- ENTRY;
-
- /* If the source and target are in the same directory, they can not
- * be parent/child relationship, so subdir check is not needed */
- if (lu_fid_eq(&dir_fid, fid))
- return 0;
-
- if (!mdt_object_exists(dir))
- RETURN(-ENOENT);
-
- rc = mdo_is_subdir(info->mti_env, mdt_object_child(dir),
- fid, &dir_fid);
- if (rc < 0) {
- CERROR("%s: failed subdir check in "DFID" for "DFID
- ": rc = %d\n", mdt_obd_name(info->mti_mdt),
- PFID(&dir_fid), PFID(fid), rc);
- /* Return EINVAL only if a parent is the @fid */
- if (rc == -EINVAL)
- rc = -EIO;
- } else {
- /* check the found fid */
- if (lu_fid_eq(&dir_fid, fid))
- rc = -EINVAL;
- }
-
- RETURN(rc);
-}
-
/* Update object linkEA */
struct mdt_lock_list {
struct mdt_object *mll_obj;
if (IS_ERR(mold))
GOTO(out_unlock_parent, rc = PTR_ERR(mold));
+ if (!mdt_object_exists(mold)) {
+ LU_OBJECT_DEBUG(D_INODE, info->mti_env,
+ &mold->mot_obj,
+ "object does not exist");
+ GOTO(out_put_child, rc = -ENOENT);
+ }
+
if (mdt_object_remote(mold)) {
CDEBUG(D_OTHER, "%s: source "DFID" is on the remote MDT\n",
mdt_obd_name(info->mti_mdt), PFID(old_fid));
}
/*
+ * determine lock order of sobj and tobj
+ *
+ * there are two situations we need to lock tobj before sobj:
+ * 1. sobj is child of tobj
+ * 2. sobj and tobj are stripes of a directory, and stripe index of sobj is
+ * larger than that of tobj
+ *
+ * \retval 1 lock tobj before sobj
+ * \retval 0 lock sobj before tobj
+ * \retval -ev negative errno upon error
+ */
+static int mdt_rename_determine_lock_order(struct mdt_thread_info *info,
+ struct mdt_object *sobj,
+ struct mdt_object *tobj)
+{
+ struct md_attr *ma = &info->mti_attr;
+ struct lu_fid *spfid = &info->mti_tmp_fid1;
+ struct lu_fid *tpfid = &info->mti_tmp_fid2;
+ struct lmv_mds_md_v1 *lmv;
+ __u32 sindex;
+ __u32 tindex;
+ int rc;
+
+ /* sobj and tobj are the same */
+ if (sobj == tobj)
+ return 0;
+
+ if (fid_is_root(mdt_object_fid(sobj)))
+ return 0;
+
+ if (fid_is_root(mdt_object_fid(tobj)))
+ return 1;
+
+ /* check whether sobj is child of tobj */
+ rc = mdo_is_subdir(info->mti_env, mdt_object_child(sobj),
+ mdt_object_fid(tobj));
+ if (rc < 0)
+ return rc;
+
+ if (rc == 1)
+ return 1;
+
+ /* check whether sobj and tobj are children of the same parent */
+ rc = mdt_attr_get_pfid(info, sobj, spfid);
+ if (rc)
+ return rc;
+
+ rc = mdt_attr_get_pfid(info, tobj, tpfid);
+ if (rc)
+ return rc;
+
+ if (!lu_fid_eq(spfid, tpfid))
+ return 0;
+
+ /* check whether sobj and tobj are sibling stripes */
+ ma->ma_need = MA_LMV;
+ ma->ma_valid = 0;
+ ma->ma_lmv = (union lmv_mds_md *)info->mti_xattr_buf;
+ ma->ma_lmv_size = sizeof(info->mti_xattr_buf);
+ rc = mdt_stripe_get(info, sobj, ma, XATTR_NAME_LMV);
+ if (rc)
+ return rc;
+
+ if (!(ma->ma_valid & MA_LMV))
+ return 0;
+
+ lmv = &ma->ma_lmv->lmv_md_v1;
+ if (!(le32_to_cpu(lmv->lmv_magic) & LMV_MAGIC_STRIPE))
+ return 0;
+ sindex = le32_to_cpu(lmv->lmv_master_mdt_index);
+
+ ma->ma_valid = 0;
+ rc = mdt_stripe_get(info, tobj, ma, XATTR_NAME_LMV);
+ if (rc)
+ return rc;
+
+ if (!(ma->ma_valid & MA_LMV))
+ return -ENODATA;
+
+ lmv = &ma->ma_lmv->lmv_md_v1;
+ if (!(le32_to_cpu(lmv->lmv_magic) & LMV_MAGIC_STRIPE))
+ return -EINVAL;
+ tindex = le32_to_cpu(lmv->lmv_master_mdt_index);
+
+ /* check stripe index of sobj and tobj */
+ if (sindex == tindex)
+ return -EINVAL;
+
+ return sindex < tindex ? 0 : 1;
+}
+
+/*
* VBR: rename versions in reply: 0 - srcdir parent; 1 - tgtdir parent;
* 2 - srcdir child; 3 - tgtdir child.
* Update on disk version of srcdir child.
struct lu_fid *new_fid = &info->mti_tmp_fid2;
__u64 lock_ibits;
bool reverse = false;
- bool cos_incompat;
+ bool cos_incompat, discard = false;
int rc;
ENTRY;
mtgtdir = msrcdir;
mdt_object_get(info->mti_env, mtgtdir);
} else {
- /* Check if the @msrcdir is not a child of the @mtgtdir,
- * otherwise a reverse locking must take place. */
- rc = mdt_is_subdir(info, msrcdir, rr->rr_fid2);
- if (rc == -EINVAL)
- reverse = true;
- else if (rc)
- GOTO(out_put_srcdir, rc);
-
mtgtdir = mdt_object_find_check(info, rr->rr_fid2, 1);
if (IS_ERR(mtgtdir))
GOTO(out_put_srcdir, rc = PTR_ERR(mtgtdir));
}
+ rc = mdt_rename_determine_lock_order(info, msrcdir, mtgtdir);
+ if (rc < 0)
+ GOTO(out_put_tgtdir, rc);
+
+ reverse = rc;
+
/* source needs to be looked up after locking source parent, otherwise
* this rename may race with unlink source, and cause rename hang, see
* sanityn.sh 55b, so check parents first, if later we found source is
if (IS_ERR(mold))
GOTO(out_unlock_parents, rc = PTR_ERR(mold));
+ if (!mdt_object_exists(mold)) {
+ LU_OBJECT_DEBUG(D_INODE, info->mti_env,
+ &mold->mot_obj,
+ "object does not exist");
+ GOTO(out_put_old, rc = -ENOENT);
+ }
+
/* Check if @mtgtdir is subdir of @mold, before locking child
* to avoid reverse locking. */
if (mtgtdir != msrcdir) {
- rc = mdt_is_subdir(info, mtgtdir, old_fid);
- if (rc)
+ rc = mdo_is_subdir(info->mti_env, mdt_object_child(mtgtdir),
+ old_fid);
+ if (rc) {
+ if (rc == 1)
+ rc = -EINVAL;
GOTO(out_put_old, rc);
+ }
}
tgt_vbr_obj_set(info->mti_env, mdt_obj2dt(mold));
if (IS_ERR(mnew))
GOTO(out_put_old, rc = PTR_ERR(mnew));
+ if (!mdt_object_exists(mnew)) {
+ LU_OBJECT_DEBUG(D_INODE, info->mti_env,
+ &mnew->mot_obj,
+ "object does not exist");
+ GOTO(out_put_new, rc = -ENOENT);
+ }
+
if (mdt_object_remote(mnew)) {
struct mdt_body *repbody;
/* Check if @msrcdir is subdir of @mnew, before locking child
* to avoid reverse locking. */
if (mtgtdir != msrcdir) {
- rc = mdt_is_subdir(info, msrcdir, new_fid);
- if (rc)
+ rc = mdo_is_subdir(info->mti_env,
+ mdt_object_child(msrcdir), new_fid);
+ if (rc) {
+ if (rc == 1)
+ rc = -EINVAL;
GOTO(out_unlock_old, rc);
+ }
}
/* We used to acquire MDS_INODELOCK_FULL here but we
mdt_counter_incr(req, LPROC_MDT_RENAME);
if (mnew) {
mdt_handle_last_unlink(info, mnew, ma);
- mdt_dom_check_and_discard(info, mnew);
+ discard = true;
}
mdt_rename_counter_tally(info, info->mti_mdt, req,
out_unlock_old:
mdt_object_unlock(info, mold, lh_oldp, rc);
out_put_new:
- if (mnew != NULL)
+ if (mnew != NULL) {
+ if (discard)
+ mdt_dom_check_and_discard(info, mnew);
mdt_object_put(info->mti_env, mnew);
+ }
out_put_old:
mdt_object_put(info->mti_env, mold);
out_unlock_parents: