static int osp_precreate_ready_condition(const struct lu_env *env, struct osp_device *d) { if (d->opd_pre_recovering) return 0; /* ready if got enough precreated objects */ /* we need to wait for others (opd_pre_reserved) and our object (+1) */ if (d->opd_pre_reserved + 1 < osp_objs_precreated(env, d)) return 1; /* ready if OST reported no space and no destroys in progress */ if (d->opd_syn_changes + d->opd_syn_rpc_in_progress == 0 && d->opd_pre_status == -ENOSPC) return 1; /* Bail out I/O fails to OST */ if (d->opd_pre_status != 0 && d->opd_pre_status != -EAGAIN && d->opd_pre_status != -ENODEV && d->opd_pre_status != -ENOSPC) { /* DEBUG LU-3230 */ if (d->opd_pre_status != -EIO) CERROR("%s: precreate failed opd_pre_status %d\n", d->opd_obd->obd_name, d->opd_pre_status); return 1; } return 0; }
static inline int osp_precreate_near_empty_nolock(const struct lu_env *env, struct osp_device *d) { int window = osp_objs_precreated(env, d); /* don't consider new precreation till OST is healty and * has free space */ return ((window - d->opd_pre_reserved < d->opd_pre_grow_count / 2) && (d->opd_pre_status == 0)); }
static int osp_precreate_ready_condition(const struct lu_env *env, struct osp_device *d) { if (d->opd_pre_recovering) return 0; /* ready if got enough precreated objects */ /* we need to wait for others (opd_pre_reserved) and our object (+1) */ if (d->opd_pre_reserved + 1 < osp_objs_precreated(env, d)) return 1; /* ready if OST reported no space and no destoys in progress */ if (d->opd_syn_changes + d->opd_syn_rpc_in_progress == 0 && d->opd_pre_status == -ENOSPC) return 1; return 0; }
/* * called to reserve object in the pool * return codes: * ENOSPC - no space on corresponded OST * EAGAIN - precreation is in progress, try later * EIO - no access to OST */ int osp_precreate_reserve(const struct lu_env *env, struct osp_device *d) { struct l_wait_info lwi; cfs_time_t expire = cfs_time_shift(obd_timeout); int precreated, rc; ENTRY; LASSERTF(osp_objs_precreated(env, d) >= 0, "Last created FID "DFID "Next FID "DFID"\n", PFID(&d->opd_pre_last_created_fid), PFID(&d->opd_pre_used_fid)); /* * wait till: * - preallocation is done * - no free space expected soon * - can't connect to OST for too long (obd_timeout) * - OST can allocate fid sequence. */ while ((rc = d->opd_pre_status) == 0 || rc == -ENOSPC || rc == -ENODEV || rc == -EAGAIN || rc == -ENOTCONN) { /* * increase number of precreations */ precreated = osp_objs_precreated(env, d); if (d->opd_pre_grow_count < d->opd_pre_max_grow_count && d->opd_pre_grow_slow == 0 && precreated <= (d->opd_pre_grow_count / 4 + 1)) { spin_lock(&d->opd_pre_lock); d->opd_pre_grow_slow = 1; d->opd_pre_grow_count *= 2; spin_unlock(&d->opd_pre_lock); } spin_lock(&d->opd_pre_lock); precreated = osp_objs_precreated(env, d); if (precreated > d->opd_pre_reserved && !d->opd_pre_recovering) { d->opd_pre_reserved++; spin_unlock(&d->opd_pre_lock); rc = 0; /* XXX: don't wake up if precreation is in progress */ if (osp_precreate_near_empty_nolock(env, d) && !osp_precreate_end_seq_nolock(env, d)) wake_up(&d->opd_pre_waitq); break; } spin_unlock(&d->opd_pre_lock); /* * all precreated objects have been used and no-space * status leave us no chance to succeed very soon * but if there is destroy in progress, then we should * wait till that is done - some space might be released */ if (unlikely(rc == -ENOSPC)) { if (d->opd_syn_changes) { /* force local commit to release space */ dt_commit_async(env, d->opd_storage); } if (d->opd_syn_rpc_in_progress) { /* just wait till destroys are done */ /* see l_wait_even() few lines below */ } if (d->opd_syn_changes + d->opd_syn_rpc_in_progress == 0) { /* no hope for free space */ break; } } /* XXX: don't wake up if precreation is in progress */ wake_up(&d->opd_pre_waitq); lwi = LWI_TIMEOUT(expire - cfs_time_current(), osp_precreate_timeout_condition, d); if (cfs_time_aftereq(cfs_time_current(), expire)) { rc = -ETIMEDOUT; break; } l_wait_event(d->opd_pre_user_waitq, osp_precreate_ready_condition(env, d), &lwi); } RETURN(rc); }