LASSERT(r0->lo_sub[idx] == NULL);
}
-static void lov_delete_raid0(const struct lu_env *env, struct lov_object *lov,
+static int lov_delete_raid0(const struct lu_env *env, struct lov_object *lov,
struct lov_layout_entry *lle)
{
struct lov_layout_raid0 *r0 = &lle->lle_raid0;
+ int rc;
ENTRY;
struct lovsub_object *los = r0->lo_sub[i];
if (los != NULL) {
- cl_object_prune(env, &los->lso_cl);
+ rc = cl_object_prune(env, &los->lso_cl);
+ if (rc)
+ RETURN(rc);
/*
* If top-level object is to be evicted from
* the cache, so are its sub-objects.
}
}
- EXIT;
+ RETURN(0);
}
static void lov_fini_raid0(const struct lu_env *env,
union lov_layout_state *state)
{
struct lov_layout_entry *entry;
+ int rc;
ENTRY;
if (entry->lle_lsme && lsme_is_foreign(entry->lle_lsme))
continue;
- lov_delete_raid0(env, lov, entry);
+ rc = lov_delete_raid0(env, lov, entry);
+ if (rc)
+ RETURN(rc);
}
RETURN(0);
struct lov_stripe_md *lsm = NULL;
struct lov_object *lov = cl2lov(obj);
int result = 0;
+ struct cl_object *top = cl_object_top(obj);
+ bool unlock_inode = false;
+ bool lock_inode_size = false;
ENTRY;
if (conf->coc_opc == OBJECT_CONF_SET &&
GOTO(out_lsm, result = 0);
}
+retry:
lov_conf_lock(lov);
if (conf->coc_opc == OBJECT_CONF_WAIT) {
if (test_bit(LO_LAYOUT_INVALID, &lov->lo_obj_flags) &&
}
result = lov_layout_change(env, lov, lsm, conf);
- if (result)
+ if (result) {
+ if (result == -EAGAIN) {
+ /**
+ * we need unlocked lov conf and get inode lock.
+ * It's possible we have already taken inode's size
+ * mutex, so we need keep such lock order, lest deadlock
+ * happens:
+ * inode lock (ll_inode_lock())
+ * inode size lock (ll_inode_size_lock())
+ * lov conf lock (lov_conf_lock())
+ *
+ * e.g.
+ * vfs_setxattr inode locked
+ * ll_lov_setstripe_ea_info inode size locked
+ * ll_prep_inode
+ * ll_file_inode_init
+ * cl_conf_set
+ * lov_conf_set lov conf locked
+ */
+ lov_conf_unlock(lov);
+ if (cl_object_inode_ops(
+ env, top, COIO_SIZE_UNLOCK, NULL) == 0)
+ lock_inode_size = true;
+
+ /* take lock in order */
+ if (cl_object_inode_ops(
+ env, top, COIO_INODE_LOCK, NULL) == 0)
+ unlock_inode = true;
+ if (lock_inode_size)
+ cl_object_inode_ops(
+ env, top, COIO_SIZE_LOCK, NULL);
+ goto retry;
+ }
set_bit(LO_LAYOUT_INVALID, &lov->lo_obj_flags);
- else
+ } else {
clear_bit(LO_LAYOUT_INVALID, &lov->lo_obj_flags);
+ }
EXIT;
out:
lov_conf_unlock(lov);
+ if (unlock_inode)
+ cl_object_inode_ops(env, top, COIO_INODE_UNLOCK, NULL);
out_lsm:
lov_lsm_put(lsm);
CDEBUG(D_INODE, DFID" lo_layout_invalid=%u\n",