+static inline bool
+lod_obj_is_ost_use_skip_cb(const struct lu_env *env, struct lod_object *lo,
+ int comp_idx, struct lod_obj_stripe_cb_data *data)
+{
+ struct lod_layout_component *comp = &lo->ldo_comp_entries[comp_idx];
+
+ return comp->llc_ost_indices == NULL;
+}
+
+static inline int
+lod_obj_is_ost_use_cb(const struct lu_env *env, struct lod_object *lo,
+ int comp_idx, struct lod_obj_stripe_cb_data *data)
+{
+ struct lod_layout_component *comp = &lo->ldo_comp_entries[comp_idx];
+ int i;
+
+ for (i = 0; i < comp->llc_stripe_count; i++) {
+ if (comp->llc_ost_indices[i] == data->locd_ost_index) {
+ data->locd_ost_index = -1;
+ return -EEXIST;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * 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 lod_qos_oss *lqo = ost->ltd_qos.ltq_oss;
+ 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] == lqo->lqo_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 obd_statfs *sfs, __u32 ost_idx,
+ __u32 speed, __u32 *s_idx,
+ struct dt_object **stripe,
+ __u32 *ost_indices,
+ struct thandle *th)
+{
+ 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
+ */
+ if (lod_qos_is_ost_used(env, ost_idx, stripe_idx))
+ 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.
+ *
+ * Allocates a new striping using round-robin algorithm. The function refreshes
+ * all the internal structures (statfs cache, array of available OSTs sorted
+ * with regard to OSS, etc). The number of stripes required is taken from the
+ * object (must be prepared by the caller), but can change if the flag
+ * LOV_USES_DEFAULT_STRIPE is supplied. The caller should ensure nobody else
+ * is trying to create a striping on the object in parallel. All the internal
+ * structures (like pools, etc) are protected and no additional locking is
+ * required. The function succeeds even if a single stripe is allocated. To save
+ * time we give priority to targets which already have objects precreated.
+ * Full OSTs are skipped (see lod_qos_dev_is_full() for the details).
+ *
+ * \param[in] env execution environment for this thread
+ * \param[in] lo LOD object
+ * \param[out] stripe striping created
+ * \param[out] ost_indices ost indices of striping created
+ * \param[in] flags allocation flags (0 or LOV_USES_DEFAULT_STRIPE)
+ * \param[in] th transaction handle
+ * \param[in] comp_idx index of ldo_comp_entries
+ *
+ * \retval 0 on success
+ * \retval -ENOSPC if not enough OSTs are found
+ * \retval negative negated errno for other failures
+ */