+ * Check is OST used in a composite layout
+ *
+ * \param[in] lo lod object
+ * \param[in] ost OST target index to check
+ *
+ * \retval false not used
+ * \retval true used
+ */
+static inline bool lod_comp_is_ost_used(const struct lu_env *env,
+ struct lod_object *lo, int ost)
+{
+ struct lod_obj_stripe_cb_data data = { { 0 } };
+
+ data.locd_ost_index = ost;
+ data.locd_comp_skip_cb = lod_obj_is_ost_use_skip_cb;
+ data.locd_comp_cb = lod_obj_is_ost_use_cb;
+
+ (void)lod_obj_for_each_stripe(env, lo, NULL, &data);
+
+ return data.locd_ost_index == -1;
+}
+
+static inline void lod_avoid_update(struct lod_object *lo,
+ struct lod_avoid_guide *lag)
+{
+ if (!lod_is_flr(lo))
+ return;
+
+ lag->lag_ost_avail--;
+}
+
+static inline bool lod_should_avoid_ost(struct lod_object *lo,
+ struct lod_avoid_guide *lag,
+ __u32 index)
+{
+ struct lod_device *lod = lu2lod_dev(lo->ldo_obj.do_lu.lo_dev);
+ struct lod_tgt_desc *ost = OST_TGT(lod, index);
+ struct lu_svr_qos *lsq = ost->ltd_qos.ltq_svr;
+ bool used = false;
+ int i;
+
+ if (!cfs_bitmap_check(lod->lod_ost_bitmap, index)) {
+ QOS_DEBUG("OST%d: been used in conflicting mirror component\n",
+ index);
+ return true;
+ }
+
+ /**
+ * we've tried our best, all available OSTs have been used in
+ * overlapped components in the other mirror
+ */
+ if (lag->lag_ost_avail == 0)
+ return false;
+
+ /* check OSS use */
+ for (i = 0; i < lag->lag_oaa_count; i++) {
+ if (lag->lag_oss_avoid_array[i] == lsq->lsq_id) {
+ used = true;
+ break;
+ }
+ }
+ /**
+ * if the OSS which OST[index] resides has not been used, we'd like to
+ * use it
+ */
+ if (!used)
+ return false;
+
+ /* if the OSS has been used, check whether the OST has been used */
+ if (!cfs_bitmap_check(lag->lag_ost_avoid_bitmap, index))
+ used = false;
+ else
+ QOS_DEBUG("OST%d: been used in conflicting mirror component\n",
+ index);
+ return used;
+}
+
+static int lod_check_and_reserve_ost(const struct lu_env *env,
+ struct lod_object *lo,
+ struct lod_layout_component *lod_comp,
+ struct obd_statfs *sfs, __u32 ost_idx,
+ __u32 speed, __u32 *s_idx,
+ struct dt_object **stripe,
+ __u32 *ost_indices,
+ struct thandle *th,
+ bool *overstriped)
+{
+ struct lod_device *lod = lu2lod_dev(lo->ldo_obj.do_lu.lo_dev);
+ struct lod_avoid_guide *lag = &lod_env_info(env)->lti_avoid;
+ struct dt_object *o;
+ __u32 stripe_idx = *s_idx;
+ int rc;
+ ENTRY;
+
+ rc = lod_statfs_and_check(env, lod, ost_idx, sfs);
+ if (rc)
+ RETURN(rc);
+
+ /*
+ * We expect number of precreated objects in f_ffree at
+ * the first iteration, skip OSPs with no objects ready
+ */
+ if (sfs->os_fprecreated == 0 && speed == 0) {
+ QOS_DEBUG("#%d: precreation is empty\n", ost_idx);
+ RETURN(rc);
+ }
+
+ /*
+ * try to use another OSP if this one is degraded
+ */
+ if (sfs->os_state & OS_STATE_DEGRADED && speed < 2) {
+ QOS_DEBUG("#%d: degraded\n", ost_idx);
+ RETURN(rc);
+ }
+
+ /*
+ * try not allocate on OST which has been used by other
+ * component
+ */
+ if (speed == 0 && lod_comp_is_ost_used(env, lo, ost_idx)) {
+ QOS_DEBUG("iter %d: OST%d used by other component\n",
+ speed, ost_idx);
+ RETURN(rc);
+ }
+
+ /**
+ * try not allocate OSTs used by conflicting component of other mirrors
+ * for the first and second time.
+ */
+ if (speed < 2 && lod_should_avoid_ost(lo, lag, ost_idx)) {
+ QOS_DEBUG("iter %d: OST%d used by conflicting mirror "
+ "component\n", speed, ost_idx);
+ RETURN(rc);
+ }
+
+ /* do not put >1 objects on a single OST, except for overstriping */
+ if (lod_qos_is_ost_used(env, ost_idx, stripe_idx)) {
+ if (lod_comp->llc_pattern & LOV_PATTERN_OVERSTRIPING)
+ *overstriped = true;
+ else
+ RETURN(rc);
+ }
+
+ o = lod_qos_declare_object_on(env, lod, ost_idx, th);
+ if (IS_ERR(o)) {
+ CDEBUG(D_OTHER, "can't declare new object on #%u: %d\n",
+ ost_idx, (int) PTR_ERR(o));
+ rc = PTR_ERR(o);
+ RETURN(rc);
+ }
+
+ /*
+ * We've successfully declared (reserved) an object
+ */
+ lod_avoid_update(lo, lag);
+ lod_qos_ost_in_use(env, stripe_idx, ost_idx);
+ stripe[stripe_idx] = o;
+ ost_indices[stripe_idx] = ost_idx;
+ OBD_FAIL_TIMEOUT(OBD_FAIL_MDS_LOV_CREATE_RACE, 2);
+ stripe_idx++;
+ *s_idx = stripe_idx;
+
+ RETURN(rc);
+}
+
+/**
+ * Allocate a striping using round-robin algorithm.