+ info = lu_context_key_get(&env->le_ctx, &fld_thread_key);
+ cfs_mutex_lock(&fld->lsf_lock);
+
+ erange = &info->fti_lrange;
+ new = &info->fti_irange;
+ *new = *add_range;
+
+ /* STEP 1: try to merge with previous range */
+ rc = fld_index_lookup(fld, env, new->lsr_start, erange);
+ if (rc == 0) {
+ /* in case of range overlap, the location must be same */
+ if (range_compare_loc(new, erange) != 0) {
+ CERROR("the start of given range "DRANGE" conflict to"
+ "an existing range "DRANGE"\n",
+ PRANGE(new), PRANGE(erange));
+ GOTO(out, rc = -EIO);
+ }
+
+ if (new->lsr_end < erange->lsr_end)
+ GOTO(out, rc);
+ do_merge = 1;
+ } else if (rc == -ENOENT) {
+ /* check for merge case: optimizes for single mds lustre.
+ * As entry does not exist, returned entry must be left side
+ * entry compared to start of new range (ref dio_lookup()).
+ * So try to merge from left.
+ */
+ if (new->lsr_start == erange->lsr_end &&
+ range_compare_loc(new, erange) == 0)
+ do_merge = 1;
+ } else {
+ /* no overlap allowed in fld, so failure in lookup is error */
+ GOTO(out, rc);
+ }
+
+ if (do_merge) {
+ /* new range will be merged with the existing one.
+ * delete this range at first. */
+ rc = fld_index_delete(fld, env, erange, th);
+ if (rc != 0)
+ GOTO(out, rc);
+
+ new->lsr_start = min(erange->lsr_start, new->lsr_start);
+ new->lsr_end = max(erange->lsr_end, new->lsr_end);
+ do_merge = 0;
+ }
+
+ /* STEP 2: try to merge with next range */
+ rc = fld_index_lookup(fld, env, new->lsr_end, erange);
+ if (rc == 0) {
+ /* found a matched range, meaning we're either
+ * overlapping or ajacent, must merge with it. */
+ do_merge = 1;
+ } else if (rc == -ENOENT) {
+ /* this range is left of new range end point */
+ LASSERT(erange->lsr_end <= new->lsr_end);
+ /*
+ * the found left range must be either:
+ * 1. withing new range.
+ * 2. left of new range (no overlapping).
+ * because if they're partly overlapping, the STEP 1 must have
+ * been removed this range.
+ */
+ LASSERTF(erange->lsr_start > new->lsr_start ||
+ erange->lsr_end < new->lsr_start ||
+ (erange->lsr_end == new->lsr_start &&
+ range_compare_loc(new, erange) != 0),
+ "left "DRANGE", new "DRANGE"\n",
+ PRANGE(erange), PRANGE(new));
+
+ /* if it's within the new range, merge it */
+ if (erange->lsr_start > new->lsr_start)
+ do_merge = 1;
+ } else {
+ GOTO(out, rc);
+ }
+
+ if (do_merge) {
+ if (range_compare_loc(new, erange) != 0) {
+ CERROR("the end of given range "DRANGE" overlaps "
+ "with an existing range "DRANGE"\n",
+ PRANGE(new), PRANGE(erange));
+ GOTO(out, rc = -EIO);
+ }
+
+ /* merge with next range */
+ rc = fld_index_delete(fld, env, erange, th);
+ if (rc != 0)
+ GOTO(out, rc);
+
+ new->lsr_start = min(erange->lsr_start, new->lsr_start);
+ new->lsr_end = max(erange->lsr_end, new->lsr_end);
+ }
+
+ /* now update fld entry. */
+ rc = fld_index_create(fld, env, new, th);
+
+ LASSERT(rc != -EEXIST);
+out:
+ if (rc == 0)
+ fld_cache_insert(fld->lsf_cache, new);
+
+ cfs_mutex_unlock(&fld->lsf_lock);
+
+ CDEBUG((rc != 0 ? D_ERROR : D_INFO),
+ "%s: FLD create: given range : "DRANGE
+ "after merge "DRANGE" rc = %d \n", fld->lsf_name,
+ PRANGE(add_range), PRANGE(new), rc);
+