spin_lock_init(&lli->lli_sa_lock);
lli->lli_opendir_pid = 0;
lli->lli_sa_enabled = 0;
+ lli->lli_def_stripe_offset = -1;
} else {
mutex_init(&lli->lli_size_mutex);
lli->lli_symlink_name = NULL;
ll_i2gids(op_data->op_suppgids, i1, i2);
op_data->op_fid1 = *ll_inode2fid(i1);
- if (S_ISDIR(i1->i_mode))
+ op_data->op_default_stripe_offset = -1;
+ if (S_ISDIR(i1->i_mode)) {
op_data->op_mea1 = ll_i2info(i1)->lli_lsm_md;
+ op_data->op_default_stripe_offset =
+ ll_i2info(i1)->lli_def_stripe_offset;
+ }
if (i2) {
op_data->op_fid2 = *ll_inode2fid(i2);
}
if (bits & MDS_INODELOCK_XATTR) {
+ if (S_ISDIR(inode->i_mode))
+ ll_i2info(inode)->lli_def_stripe_offset = -1;
ll_xattr_cache_destroy(inode);
bits &= ~MDS_INODELOCK_XATTR;
}
if (unlikely(tgt))
tgt_len = strlen(tgt) + 1;
-
+again:
op_data = ll_prep_md_op_data(NULL, dir, NULL,
dentry->d_name.name,
dentry->d_name.len,
from_kgid(&init_user_ns, current_fsgid()),
cfs_curproc_cap_pack(), rdev, &request);
ll_finish_md_op_data(op_data);
- if (err)
+ if (err < 0 && err != -EREMOTE)
goto err_exit;
+ /*
+ * If the client doesn't know where to create a subdirectory (or
+ * in case of a race that sends the RPC to the wrong MDS), the
+ * MDS will return -EREMOTE and the client will fetch the layout
+ * of the directory, then create the directory on the right MDT.
+ */
+ if (unlikely(err == -EREMOTE)) {
+ struct ll_inode_info *lli = ll_i2info(dir);
+ struct lmv_user_md *lum;
+ int lumsize, err2;
+
+ ptlrpc_req_finished(request);
+ request = NULL;
+
+ err2 = ll_dir_getstripe(dir, (void **)&lum, &lumsize, &request,
+ OBD_MD_DEFAULT_MEA);
+ if (!err2) {
+ /* Update stripe_offset and retry */
+ lli->lli_def_stripe_offset = lum->lum_stripe_offset;
+ } else if (err2 == -ENODATA &&
+ lli->lli_def_stripe_offset != -1) {
+ /*
+ * If there are no default stripe EA on the MDT, but the
+ * client has default stripe, then it probably means
+ * default stripe EA has just been deleted.
+ */
+ lli->lli_def_stripe_offset = -1;
+ } else {
+ goto err_exit;
+ }
+
+ ptlrpc_req_finished(request);
+ request = NULL;
+ goto again;
+ }
+
ll_update_times(request, dir);
err = ll_prep_inode(&inode, request, dir->i_sb, NULL);
d_instantiate(dentry, inode);
err_exit:
- ptlrpc_req_finished(request);
+ if (request)
+ ptlrpc_req_finished(request);
return err;
}