#define OBD_MD_FLLAZYBLOCKS (0x0800000000000000ULL) /* Lazy blocks */
#define OBD_MD_FLBTIME (0x1000000000000000ULL) /* birth time */
#define OBD_MD_ENCCTX (0x2000000000000000ULL) /* embed encryption ctx */
+#define OBD_MD_NAMEHASH (0x4000000000000000ULL) /* use hash instead of name
+ * in case of encryption
+ */
#define OBD_MD_FLALLQUOTA (OBD_MD_FLUSRQUOTA | \
OBD_MD_FLGRPQUOTA | \
MDS_CLOSE_UPDATE_TIMES = 1 << 20,
/* setstripe create only, don't restripe if target exists */
MDS_SETSTRIPE_CREATE = 1 << 21,
+ MDS_FID_OP = 1 << 22,
};
#define MDS_CLOSE_INTENT (MDS_HSM_RELEASE | MDS_CLOSE_LAYOUT_SWAP | \
#define MDS_OPEN_RESYNC 04000000000000ULL /* FLR: file resync */
#define MDS_OPEN_PCC 010000000000000ULL /* PCC: auto RW-PCC cache attach
* for newly created file */
+#define MDS_OP_WITH_FID 020000000000000ULL /* operation carried out by FID */
/* lustre internal open flags, which should not be set from user space */
#define MDS_OPEN_FL_INTERNAL (MDS_OPEN_HAS_EA | MDS_OPEN_HAS_OBJS | \
MDS_OPEN_OWNEROVERRIDE | MDS_OPEN_LOCK | \
MDS_OPEN_BY_FID | MDS_OPEN_LEASE | \
MDS_OPEN_RELEASE | MDS_OPEN_RESYNC | \
- MDS_OPEN_PCC)
+ MDS_OPEN_PCC | MDS_OP_WITH_FID)
/********* Changelogs **********/
* ->lookup() or we're finding the dir_entry for deletion; 0 if we cannot
* proceed without the key because we're going to create the dir_entry.
* @fname: the filename information to be filled in
+ * @fid: fid retrieved from user-provided filename
*
* This overlay function is necessary to properly encode @fname after
* encryption, as it will be sent over the wire.
+ * This overlay function is also necessary to handle the case of operations
+ * carried out without the key. Normally llcrypt makes use of digested names in
+ * that case. Having a digested name works for local file systems that can call
+ * llcrypt_match_name(), but Lustre server side is not aware of encryption.
+ * So for keyless @lookup operations on long names, for Lustre we choose to
+ * present to users the encoded struct ll_digest_filename, instead of a digested
+ * name. FID and name hash can then easily be extracted and put into the
+ * requests sent to servers.
*/
int ll_setup_filename(struct inode *dir, const struct qstr *iname,
- int lookup, struct llcrypt_name *fname)
+ int lookup, struct llcrypt_name *fname,
+ struct lu_fid *fid)
{
+ int digested = 0;
+ struct qstr dname;
int rc;
- rc = llcrypt_setup_filename(dir, iname, lookup, fname);
+ if (fid && IS_ENCRYPTED(dir) && !llcrypt_has_encryption_key(dir) &&
+ iname->name[0] == '_')
+ digested = 1;
+
+ dname.name = iname->name + digested;
+ dname.len = iname->len - digested;
+
+ if (fid) {
+ fid->f_seq = 0;
+ fid->f_oid = 0;
+ fid->f_ver = 0;
+ }
+ rc = llcrypt_setup_filename(dir, &dname, lookup, fname);
if (rc)
return rc;
+ if (digested) {
+ /* Without the key, for long names user should have struct
+ * ll_digest_filename representation of the dentry instead of
+ * the name. So make sure it is valid, return fid and put
+ * excerpt of cipher text name in disk_name.
+ */
+ struct ll_digest_filename *digest;
+
+ if (fname->crypto_buf.len < sizeof(struct ll_digest_filename)) {
+ rc = -EINVAL;
+ goto out_free;
+ }
+ digest = (struct ll_digest_filename *)fname->crypto_buf.name;
+ *fid = digest->ldf_fid;
+ if (!fid_is_sane(fid)) {
+ rc = -EINVAL;
+ goto out_free;
+ }
+ fname->disk_name.name = digest->ldf_excerpt;
+ fname->disk_name.len = LLCRYPT_FNAME_DIGEST_SIZE;
+ }
if (IS_ENCRYPTED(dir) &&
!name_is_dot_or_dotdot(fname->disk_name.name,
fname->disk_name.len)) {
* @minor_hash: minor hash for inode
* @iname: the user-provided filename needing conversion
* @oname: the filename information to be filled in
+ * @fid: the user-provided fid for filename
*
* The caller must have allocated sufficient memory for the @oname string.
*
* This overlay function is necessary to properly decode @iname before
* decryption, as it comes from the wire.
+ * This overlay function is also necessary to handle the case of operations
+ * carried out without the key. Normally llcrypt makes use of digested names in
+ * that case. Having a digested name works for local file systems that can call
+ * llcrypt_match_name(), but Lustre server side is not aware of encryption.
+ * So for keyless @lookup operations on long names, for Lustre we choose to
+ * present to users the encoded struct ll_digest_filename, instead of a digested
+ * name. FID and name hash can then easily be extracted and put into the
+ * requests sent to servers.
*/
int ll_fname_disk_to_usr(struct inode *inode,
u32 hash, u32 minor_hash,
- struct llcrypt_str *iname, struct llcrypt_str *oname)
+ struct llcrypt_str *iname, struct llcrypt_str *oname,
+ struct lu_fid *fid)
{
struct llcrypt_str lltr = LLTR_INIT(iname->name, iname->len);
+ struct ll_digest_filename digest;
+ int digested = 0;
char *buf = NULL;
int rc;
- if (IS_ENCRYPTED(inode) &&
- !name_is_dot_or_dotdot(lltr.name, lltr.len) &&
- strnchr(lltr.name, lltr.len, '=')) {
- /* Only proceed to critical decode if
- * iname contains espace char '='.
- */
- int len = lltr.len;
-
- buf = kmalloc(len, GFP_NOFS);
- if (!buf)
- return -ENOMEM;
-
- len = critical_decode(lltr.name, len, buf);
- lltr.name = buf;
- lltr.len = len;
+ if (IS_ENCRYPTED(inode)) {
+ if (!name_is_dot_or_dotdot(lltr.name, lltr.len) &&
+ strnchr(lltr.name, lltr.len, '=')) {
+ /* Only proceed to critical decode if
+ * iname contains espace char '='.
+ */
+ int len = lltr.len;
+
+ buf = kmalloc(len, GFP_NOFS);
+ if (!buf)
+ return -ENOMEM;
+
+ len = critical_decode(lltr.name, len, buf);
+ lltr.name = buf;
+ lltr.len = len;
+ }
+ if (lltr.len > LLCRYPT_FNAME_MAX_UNDIGESTED_SIZE &&
+ !llcrypt_has_encryption_key(inode) &&
+ likely(llcrypt_policy_has_filename_enc(inode))) {
+ digested = 1;
+ /* Without the key for long names, set the dentry name
+ * to the representing struct ll_digest_filename. It
+ * will be encoded by llcrypt for display, and will
+ * enable further lookup requests.
+ */
+ if (!fid)
+ return -EINVAL;
+ digest.ldf_fid = *fid;
+ memcpy(digest.ldf_excerpt,
+ LLCRYPT_FNAME_DIGEST(lltr.name, lltr.len),
+ LLCRYPT_FNAME_DIGEST_SIZE);
+
+ lltr.name = (char *)&digest;
+ lltr.len = sizeof(digest);
+
+ oname->name[0] = '_';
+ oname->name = oname->name + 1;
+ oname->len--;
+ }
}
rc = llcrypt_fname_disk_to_usr(inode, hash, minor_hash, &lltr, oname);
kfree(buf);
+ oname->name = oname->name - digested;
+ oname->len = oname->len + digested;
return rc;
}
}
int ll_setup_filename(struct inode *dir, const struct qstr *iname,
- int lookup, struct llcrypt_name *fname)
+ int lookup, struct llcrypt_name *fname,
+ struct lu_fid *fid)
{
+ if (fid) {
+ fid->f_seq = 0;
+ fid->f_oid = 0;
+ fid->f_ver = 0;
+ }
+
return llcrypt_setup_filename(dir, iname, lookup, fname);
}
int ll_fname_disk_to_usr(struct inode *inode,
u32 hash, u32 minor_hash,
- struct llcrypt_str *iname, struct llcrypt_str *oname)
+ struct llcrypt_str *iname, struct llcrypt_str *oname,
+ struct lu_fid *fid)
{
return llcrypt_fname_disk_to_usr(inode, hash, minor_hash, iname, oname);
}
LLTR_INIT(ent->lde_name, namelen);
rc = ll_fname_disk_to_usr(inode, 0, 0, &de_name,
- &lltr);
+ &lltr, &fid);
de_name = lltr;
lltr.len = save_len;
if (rc) {
}
/* crypto.c */
+/* The digested form is made of a FID (16 bytes) followed by the second-to-last
+ * ciphertext block (16 bytes), so a total length of 32 bytes.
+ * That way, llcrypt does not compute a digested form of this digest.
+ */
+struct ll_digest_filename {
+ struct lu_fid ldf_fid;
+ char ldf_excerpt[LLCRYPT_FNAME_DIGEST_SIZE];
+};
+
int ll_setup_filename(struct inode *dir, const struct qstr *iname,
- int lookup, struct llcrypt_name *fname);
+ int lookup, struct llcrypt_name *fname,
+ struct lu_fid *fid);
int ll_fname_disk_to_usr(struct inode *inode,
u32 hash, u32 minor_hash,
- struct llcrypt_str *iname, struct llcrypt_str *oname);
+ struct llcrypt_str *iname, struct llcrypt_str *oname,
+ struct lu_fid *fid);
int ll_revalidate_d_crypto(struct dentry *dentry, unsigned int flags);
#ifdef HAVE_LUSTRE_CRYPTO
extern const struct llcrypt_operations lustre_cryptops;
} else if (name && namelen) {
struct qstr dname = QSTR_INIT(name, namelen);
struct inode *dir;
+ struct lu_fid *pfid = NULL;
+ struct lu_fid fid;
int lookup;
if (!S_ISDIR(i1->i_mode) && i2 && S_ISDIR(i2->i_mode)) {
dir = i1;
lookup = (int)(opc == LUSTRE_OPC_ANY);
}
- rc = ll_setup_filename(dir, &dname, lookup, &fname);
+ if (opc == LUSTRE_OPC_ANY && lookup)
+ pfid = &fid;
+ rc = ll_setup_filename(dir, &dname, lookup, &fname, pfid);
if (rc) {
ll_finish_md_op_data(op_data);
return ERR_PTR(rc);
}
+ if (pfid && !fid_is_zero(pfid)) {
+ if (i2 == NULL)
+ op_data->op_fid2 = fid;
+ op_data->op_bias = MDS_FID_OP;
+ }
if (fname.disk_name.name &&
fname.disk_name.name != (unsigned char *)name)
/* op_data->op_name must be freed after use */
int rc;
char secctx_name[XATTR_NAME_MAX + 1];
struct llcrypt_name fname;
-
+ struct lu_fid fid;
ENTRY;
if (dentry->d_name.len > ll_i2sbi(parent)->ll_namelen)
* not exported function) and call it from ll_revalidate_dentry(), to
* ensure we do not cache stale dentries after a key has been added.
*/
- rc = ll_setup_filename(parent, &dentry->d_name, 1, &fname);
+ rc = ll_setup_filename(parent, &dentry->d_name, 1, &fname, &fid);
if ((!rc || rc == -ENOENT) && fname.is_ciphertext_name) {
spin_lock(&dentry->d_lock);
dentry->d_flags |= DCACHE_ENCRYPTED_NAME;
llcrypt_free_filename(&fname);
RETURN(ERR_CAST(op_data));
}
+ if (!fid_is_zero(&fid)) {
+ op_data->op_fid2 = fid;
+ op_data->op_bias = MDS_FID_OP;
+ if (it->it_op & IT_OPEN)
+ it->it_flags |= MDS_OPEN_BY_FID;
+ }
/* enforce umask if acl disabled or MDS doesn't support umask */
if (!IS_POSIXACL(parent) || !exp_connect_umask(ll_i2mdexp(parent)))
if (dchild->d_inode != NULL)
op_data->op_fid3 = *ll_inode2fid(dchild->d_inode);
- op_data->op_fid2 = op_data->op_fid3;
+ if (fid_is_zero(&op_data->op_fid2))
+ op_data->op_fid2 = op_data->op_fid3;
rc = md_unlink(ll_i2sbi(dir)->ll_md_exp, op_data, &request);
ll_finish_md_op_data(op_data);
if (!rc) {
ll_i2info(dchild->d_inode)->lli_clob &&
dirty_cnt(dchild->d_inode))
op_data->op_cli_flags |= CLI_DIRTY_DATA;
- op_data->op_fid2 = op_data->op_fid3;
+ if (fid_is_zero(&op_data->op_fid2))
+ op_data->op_fid2 = op_data->op_fid3;
rc = md_unlink(ll_i2sbi(dir)->ll_md_exp, op_data, &request);
ll_finish_md_op_data(op_data);
if (rc)
if (tgt_dchild->d_inode)
op_data->op_fid4 = *ll_inode2fid(tgt_dchild->d_inode);
- err = ll_setup_filename(src, &src_dchild->d_name, 1, &foldname);
+ err = ll_setup_filename(src, &src_dchild->d_name, 1, &foldname, NULL);
if (err)
RETURN(err);
- err = ll_setup_filename(tgt, &tgt_dchild->d_name, 1, &fnewname);
+ err = ll_setup_filename(tgt, &tgt_dchild->d_name, 1, &fnewname, NULL);
if (err) {
llcrypt_free_filename(&foldname);
RETURN(err);
if (IS_ENCRYPTED(dir)) {
struct llcrypt_str de_name =
LLTR_INIT(ent->lde_name, namelen);
+ struct lu_fid fid;
rc = llcrypt_fname_alloc_buffer(dir, NAME_MAX,
&lltr);
if (rc < 0)
continue;
+ fid_le_to_cpu(&fid, &ent->lde_fid);
if (ll_fname_disk_to_usr(dir, 0, 0, &de_name,
- &lltr)) {
+ &lltr, &fid)) {
llcrypt_fname_free_buffer(&lltr);
continue;
}
if (IS_ENCRYPTED(dir)) {
struct llcrypt_str de_name =
LLTR_INIT(ent->lde_name, namelen);
+ struct lu_fid fid;
+ fid_le_to_cpu(&fid, &ent->lde_fid);
if (ll_fname_disk_to_usr(dir, 0, 0, &de_name,
- &lltr))
+ &lltr, &fid))
continue;
name = lltr.name;
namelen = lltr.len;
b->mbo_valid = valid;
if (op_data->op_bias & MDS_CROSS_REF)
b->mbo_valid |= OBD_MD_FLCROSSREF;
+ if (op_data->op_bias & MDS_FID_OP)
+ b->mbo_valid |= OBD_MD_NAMEHASH;
b->mbo_eadatasize = ea_size;
b->mbo_flags = flags;
__mdc_pack_body(b, op_data->op_suppgids[0]);
it->it_flags);
lockh.cookie = 0;
+ /* MDS_FID_OP is not a revalidate case */
if (fid_is_sane(&op_data->op_fid2) &&
- (it->it_op & (IT_LOOKUP | IT_GETATTR | IT_READDIR))) {
+ (it->it_op & (IT_LOOKUP | IT_GETATTR | IT_READDIR)) &&
+ !(op_data->op_bias & MDS_FID_OP)) {
/* We could just return 1 immediately, but since we should only
* be called in revalidate_it if we already have a lock, let's
* verify that.
op_data->op_mode);
req_capsule_set_size(&req->rq_pill, &RMF_ACL, RCL_SERVER, acl_bufsize);
ptlrpc_request_set_replen(req);
+ if (op_data->op_bias & MDS_FID_OP) {
+ struct mdt_body *b = req_capsule_client_get(&req->rq_pill,
+ &RMF_MDT_BODY);
+
+ if (b) {
+ b->mbo_valid |= OBD_MD_NAMEHASH;
+ b->mbo_fid2 = op_data->op_fid2;
+ }
+ }
rc = mdc_getattr_common(exp, req);
if (rc) {
#include <lustre_barrier.h>
#include <obd_cksum.h>
#include <llog_swab.h>
+#include <lustre_crypto.h>
#include "mdt_internal.h"
RETURN(rc);
}
+/**
+ * Find name matching hash
+ *
+ * We search \a child LinkEA for a name whose hash matches \a lname
+ * (it contains an encoded hash).
+ *
+ * \param info mdt thread info
+ * \param lname encoded hash to find
+ * \param parent parent object
+ * \param child object to search with LinkEA
+ * \param force_check true to check hash even if LinkEA has only one entry
+ *
+ * \retval 1 match found
+ * \retval 0 no match found
+ * \retval -ev negative errno upon error
+ */
+int find_name_matching_hash(struct mdt_thread_info *info, struct lu_name *lname,
+ struct mdt_object *parent, struct mdt_object *child,
+ bool force_check)
+{
+ /* Here, lname is an encoded hash of on-disk name, and
+ * client is doing access without encryption key.
+ * So we need to get LinkEA, check parent fid is correct and
+ * compare name hash with the one in the request.
+ */
+ struct lu_buf *buf = &info->mti_big_buf;
+ struct lu_name name;
+ struct lu_fid pfid;
+ struct linkea_data ldata = { NULL };
+ struct link_ea_header *leh;
+ struct link_ea_entry *lee;
+ struct lu_buf link = { 0 };
+ char *hash = NULL;
+ int reclen, count, rc;
+
+ ENTRY;
+
+ if (lname->ln_namelen < LLCRYPT_FNAME_DIGEST_SIZE)
+ RETURN(-EINVAL);
+
+ buf = lu_buf_check_and_alloc(buf, PATH_MAX);
+ if (!buf->lb_buf)
+ RETURN(-ENOMEM);
+
+ ldata.ld_buf = buf;
+ rc = mdt_links_read(info, child, &ldata);
+ if (rc < 0)
+ RETURN(rc);
+
+ leh = buf->lb_buf;
+ if (force_check || leh->leh_reccount > 1) {
+ hash = kmalloc(lname->ln_namelen, GFP_NOFS);
+ if (!hash)
+ RETURN(-ENOMEM);
+ rc = critical_decode(lname->ln_name, lname->ln_namelen, hash);
+ }
+ lee = (struct link_ea_entry *)(leh + 1);
+ for (count = 0; count < leh->leh_reccount; count++) {
+ linkea_entry_unpack(lee, &reclen, &name, &pfid);
+ if (!force_check && leh->leh_reccount == 1) {
+ /* if there is only one rec, it has to be it */
+ *lname = name;
+ break;
+ }
+ if (!parent || lu_fid_eq(&pfid, mdt_object_fid(parent))) {
+ lu_buf_check_and_alloc(&link, name.ln_namelen);
+ if (!link.lb_buf)
+ GOTO(out_match, rc = -ENOMEM);
+ rc = critical_decode(name.ln_name, name.ln_namelen,
+ link.lb_buf);
+
+ if (memcmp(LLCRYPT_FNAME_DIGEST(link.lb_buf, rc),
+ hash, LLCRYPT_FNAME_DIGEST_SIZE) == 0) {
+ *lname = name;
+ break;
+ }
+ }
+ lee = (struct link_ea_entry *) ((char *)lee + reclen);
+ }
+ if (count == leh->leh_reccount)
+ rc = 0;
+ else
+ rc = 1;
+
+out_match:
+ lu_buf_free(&link);
+ kfree(hash);
+
+ RETURN(rc);
+}
+
/*
* UPDATE lock should be taken against parent, and be released before exit;
* child_bits lock should be taken against child, and be returned back:
lname = &info->mti_name;
mdt_name_unpack(pill, &RMF_NAME, lname, MNF_FIX_ANON);
- if (lu_name_is_valid(lname)) {
+ if (info->mti_body->mbo_valid & OBD_MD_NAMEHASH) {
+ reqbody = req_capsule_client_get(pill, &RMF_MDT_BODY);
+ if (unlikely(reqbody == NULL))
+ RETURN(err_serious(-EPROTO));
+
+ *child_fid = reqbody->mbo_fid2;
+ if (unlikely(!fid_is_sane(child_fid)))
+ RETURN(err_serious(-EINVAL));
+
+ if (lu_fid_eq(mdt_object_fid(parent), child_fid)) {
+ mdt_object_get(info->mti_env, parent);
+ child = parent;
+ } else {
+ child = mdt_object_find(info->mti_env, info->mti_mdt,
+ child_fid);
+ if (IS_ERR(child))
+ RETURN(PTR_ERR(child));
+ }
+
+ CDEBUG(D_INODE, "getattr with lock for "DFID"/"DFID", "
+ "ldlm_rep = %p\n",
+ PFID(mdt_object_fid(parent)),
+ PFID(&reqbody->mbo_fid2), ldlm_rep);
+ } else if (lu_name_is_valid(lname)) {
if (mdt_object_remote(parent)) {
CERROR("%s: parent "DFID" is on remote target\n",
mdt_obd_name(info->mti_mdt),
mdt_set_disposition(info, ldlm_rep, DISP_LOOKUP_EXECD);
- if (unlikely(!mdt_object_exists(parent)) && lu_name_is_valid(lname)) {
+ if (unlikely(!mdt_object_exists(parent)) &&
+ !(info->mti_body->mbo_valid & OBD_MD_NAMEHASH) &&
+ lu_name_is_valid(lname)) {
LU_OBJECT_DEBUG(D_INODE, info->mti_env,
&parent->mot_obj,
"Parent doesn't exist!");
GOTO(out_child, rc = -ESTALE);
}
- if (lu_name_is_valid(lname)) {
+ if (!(info->mti_body->mbo_valid & OBD_MD_NAMEHASH) &&
+ lu_name_is_valid(lname)) {
if (info->mti_body->mbo_valid == OBD_MD_FLID) {
rc = mdt_raw_lookup(info, parent, lname);
/* step 3: lock child regardless if it is local or remote. */
LASSERT(child);
+ if (info->mti_body->mbo_valid & OBD_MD_NAMEHASH) {
+ /* Here, lname is an encoded hash of on-disk name, and
+ * client is doing access without encryption key.
+ * So we need to compare name hash with the one in the request.
+ */
+ if (!find_name_matching_hash(info, lname, parent,
+ child, true)) {
+ mdt_set_disposition(info, ldlm_rep, DISP_LOOKUP_NEG);
+ mdt_clear_disposition(info, ldlm_rep, DISP_LOOKUP_POS);
+ GOTO(out_child, rc = -ENOENT);
+ }
+ }
+
OBD_FAIL_TIMEOUT(OBD_FAIL_MDS_RESEND, obd_timeout * 2);
if (!mdt_object_exists(child)) {
LU_OBJECT_DEBUG(D_INODE, info->mti_env,
RETURN(rc);
}
- if (mdt_object_remote(obj))
+ if (mdt_object_remote(obj)) {
rc = -EREMOTE;
- else if (!mdt_object_exists(obj))
+ } else if (!mdt_object_exists(obj)) {
rc = -ENOENT;
- else
- rc = 0;
+ } else {
+ struct lu_attr la = { 0 };
+ struct dt_object *dt = mdt_obj2dt(obj);
+
+ if (dt && dt->do_ops && dt->do_ops->do_attr_get)
+ dt_attr_get(info->mti_env, mdt_obj2dt(obj), &la);
+ if (la.la_valid & LA_FLAGS && la.la_flags & LUSTRE_ENCRYPT_FL)
+ /* path resolution cannot be carried out on server
+ * side for encrypted files
+ */
+ rc = -ENODATA;
+ else
+ rc = 0;
+ }
if (rc < 0) {
mdt_object_put(info->mti_env, obj);
int mdt_layout_change(struct mdt_thread_info *info, struct mdt_object *obj,
struct mdt_lock_handle *lhc,
struct md_layout_change *spec);
+int find_name_matching_hash(struct mdt_thread_info *info, struct lu_name *lname,
+ struct mdt_object *parent, struct mdt_object *child,
+ bool force_check);
int mdt_device_sync(const struct lu_env *env, struct mdt_device *mdt);
struct lu_buf *mdt_buf(const struct lu_env *env, void *area, ssize_t len);
attr->la_mtime = rec->ul_time;
attr->la_mode = rec->ul_mode;
attr->la_valid = LA_UID | LA_GID | LA_CTIME | LA_MTIME | LA_MODE;
+ if (rec->ul_bias & MDS_FID_OP)
+ info->mti_spec.sp_cr_flags |= MDS_OP_WITH_FID;
+ else
+ info->mti_spec.sp_cr_flags &= ~MDS_OP_WITH_FID;
rc = mdt_name_unpack(pill, &RMF_NAME, &rr->rr_name, 0);
if (rc < 0)
#include <lprocfs_status.h>
#include "mdt_internal.h"
#include <lustre_lmv.h>
+#include <lustre_crypto.h>
static inline void mdt_reint_init_ma(struct mdt_thread_info *info,
struct md_attr *ma)
if (rc != 0)
GOTO(put_parent, rc);
- /* lookup child object along with version checking */
- fid_zero(child_fid);
- rc = mdt_lookup_version_check(info, mp, &rr->rr_name, child_fid, 1);
- if (rc != 0) {
- /* Name might not be able to find during resend of
- * remote unlink, considering following case.
- * dir_A is a remote directory, the name entry of
- * dir_A is on MDT0, the directory is on MDT1,
- *
- * 1. client sends unlink req to MDT1.
- * 2. MDT1 sends name delete update to MDT0.
- * 3. name entry is being deleted in MDT0 synchronously.
- * 4. MDT1 is restarted.
- * 5. client resends unlink req to MDT1. So it can not
- * find the name entry on MDT0 anymore.
- * In this case, MDT1 only needs to destory the local
- * directory.
- */
- if (mdt_object_remote(mp) && rc == -ENOENT &&
- !fid_is_zero(rr->rr_fid2) &&
- lustre_msg_get_flags(req->rq_reqmsg) & MSG_RESENT) {
- no_name = 1;
- *child_fid = *rr->rr_fid2;
- } else {
- GOTO(unlock_parent, rc);
+ if (info->mti_spec.sp_cr_flags & MDS_OP_WITH_FID) {
+ *child_fid = *rr->rr_fid2;
+ } else {
+ /* lookup child object along with version checking */
+ fid_zero(child_fid);
+ rc = mdt_lookup_version_check(info, mp, &rr->rr_name, child_fid,
+ 1);
+ if (rc != 0) {
+ /* Name might not be able to find during resend of
+ * remote unlink, considering following case.
+ * dir_A is a remote directory, the name entry of
+ * dir_A is on MDT0, the directory is on MDT1,
+ *
+ * 1. client sends unlink req to MDT1.
+ * 2. MDT1 sends name delete update to MDT0.
+ * 3. name entry is being deleted in MDT0 synchronously.
+ * 4. MDT1 is restarted.
+ * 5. client resends unlink req to MDT1. So it can not
+ * find the name entry on MDT0 anymore.
+ * In this case, MDT1 only needs to destory the local
+ * directory.
+ */
+ if (mdt_object_remote(mp) && rc == -ENOENT &&
+ !fid_is_zero(rr->rr_fid2) &&
+ lustre_msg_get_flags(req->rq_reqmsg) & MSG_RESENT) {
+ no_name = 1;
+ *child_fid = *rr->rr_fid2;
+ } else {
+ GOTO(unlock_parent, rc);
+ }
}
}
if (IS_ERR(mc))
GOTO(unlock_parent, rc = PTR_ERR(mc));
+ if (info->mti_spec.sp_cr_flags & MDS_OP_WITH_FID) {
+ /* In this case, child fid is embedded in the request, and we do
+ * not have a proper name as rr_name contains an encoded
+ * hash. So find name that matches provided hash.
+ */
+ if (!find_name_matching_hash(info, &rr->rr_name,
+ NULL, mc, false))
+ GOTO(put_child, rc = -ENOENT);
+ }
+
if (!cos_incompat) {
rc = mdt_object_striped(info, mc);
if (rc < 0)
unlock_child:
mdt_reint_striped_unlock(info, mc, child_lh, einfo, rc);
put_child:
+ if (info->mti_spec.sp_cr_flags & MDS_OP_WITH_FID &&
+ info->mti_big_buf.lb_buf)
+ lu_buf_free(&info->mti_big_buf);
mdt_object_put(info->mti_env, mc);
unlock_parent:
mdt_object_unlock(info, mp, parent_lh, rc);
test_46() {
local testdir=$DIR/$tdir/mydir
local testfile=$testdir/myfile
- local testdir2=$DIR/$tdir/mydir2
- local testfile2=$testdir/myfile2
+ local testdir2=$DIR/$tdir/mydirwithaveryverylongnametotestcodebehaviour0
+ local testfile2=$testdir/myfilewithaveryverylongnametotestcodebehaviour0
local lsfile=$TMP/lsfile
local scrambleddir
local scrambledfile
mkdir $testdir
echo test > $testfile
echo othertest > $testfile2
+ if [[ $MDSCOUNT -gt 1 ]]; then
+ $LFS setdirstripe -c1 -i1 $testdir2
+ else
+ mkdir $testdir2
+ fi
sync ; echo 3 > /proc/sys/vm/drop_caches
# remove fscrypt key from keyring
keyctl reap
cancel_lru_locks
+ # this is $testdir2
+ scrambleddir=$(find $DIR/$tdir/ -maxdepth 1 -mindepth 1 -type d| grep _)
+ stat $scrambleddir || error "stat $scrambleddir failed"
+ rmdir $scrambleddir || error "rmdir $scrambleddir failed"
+
scrambleddir=$(find $DIR/$tdir/ -maxdepth 1 -mindepth 1 -type d)
ls -1 $scrambleddir > $lsfile || error "ls $testdir failed (1)"
test_54() {
local testdir=$DIR/$tdir/$ID0
local testfile=$testdir/$tfile
- local testfile2=$testdir/${tfile}2
+ local testfile2=$testdir/${tfile}withveryverylongnametoexercisecode
local tmpfile=$TMP/${tfile}.tmp
local resfile=$TMP/${tfile}.res