static int osp_statfs_interpret(const struct lu_env *env, struct ptlrpc_request *req, union ptlrpc_async_args *aa, int rc) { struct obd_import *imp = req->rq_import; struct obd_statfs *msfs; struct osp_device *d; ENTRY; aa = ptlrpc_req_async_args(req); d = aa->pointer_arg[0]; LASSERT(d); if (rc != 0) GOTO(out, rc); msfs = req_capsule_server_get(&req->rq_pill, &RMF_OBD_STATFS); if (msfs == NULL) GOTO(out, rc = -EPROTO); d->opd_statfs = *msfs; osp_pre_update_status(d, rc); /* schedule next update */ d->opd_statfs_fresh_till = cfs_time_shift(d->opd_statfs_maxage); cfs_timer_arm(&d->opd_statfs_timer, d->opd_statfs_fresh_till); d->opd_statfs_update_in_progress = 0; CDEBUG(D_CACHE, "updated statfs %p\n", d); RETURN(0); out: /* couldn't update statfs, try again as soon as possible */ if (d->opd_pre != NULL && osp_precreate_running(d)) wake_up(&d->opd_pre_waitq); if (req->rq_import_generation == imp->imp_generation) CDEBUG(D_CACHE, "%s: couldn't update statfs: rc = %d\n", d->opd_obd->obd_name, rc); RETURN(rc); }
/** * asks OST to clean precreate orphans * and gets next id for new objects */ static int osp_precreate_cleanup_orphans(struct lu_env *env, struct osp_device *d) { struct osp_thread_info *osi = osp_env_info(env); struct lu_fid *last_fid = &osi->osi_fid; struct ptlrpc_request *req = NULL; struct obd_import *imp; struct ost_body *body; struct l_wait_info lwi = { 0 }; int update_status = 0; int rc; int diff; ENTRY; /* * wait for local recovery to finish, so we can cleanup orphans * orphans are all objects since "last used" (assigned), but * there might be objects reserved and in some cases they won't * be used. we can't cleanup them till we're sure they won't be * used. also can't we allow new reservations because they may * end up getting orphans being cleaned up below. so we block * new reservations and wait till all reserved objects either * user or released. */ spin_lock(&d->opd_pre_lock); d->opd_pre_recovering = 1; spin_unlock(&d->opd_pre_lock); /* * The locking above makes sure the opd_pre_reserved check below will * catch all osp_precreate_reserve() calls who find * "!opd_pre_recovering". */ l_wait_event(d->opd_pre_waitq, (!d->opd_pre_reserved && d->opd_recovery_completed) || !osp_precreate_running(d) || d->opd_got_disconnected, &lwi); if (!osp_precreate_running(d) || d->opd_got_disconnected) GOTO(out, rc = -EAGAIN); CDEBUG(D_HA, "%s: going to cleanup orphans since "DFID"\n", d->opd_obd->obd_name, PFID(&d->opd_last_used_fid)); *last_fid = d->opd_last_used_fid; /* The OSP should already get the valid seq now */ LASSERT(!fid_is_zero(last_fid)); if (fid_oid(&d->opd_last_used_fid) < 2) { /* lastfid looks strange... ask OST */ rc = osp_get_lastfid_from_ost(env, d); if (rc) GOTO(out, rc); } imp = d->opd_obd->u.cli.cl_import; LASSERT(imp); req = ptlrpc_request_alloc(imp, &RQF_OST_CREATE); if (req == NULL) GOTO(out, rc = -ENOMEM); rc = ptlrpc_request_pack(req, LUSTRE_OST_VERSION, OST_CREATE); if (rc) { ptlrpc_request_free(req); req = NULL; GOTO(out, rc); } body = req_capsule_client_get(&req->rq_pill, &RMF_OST_BODY); if (body == NULL) GOTO(out, rc = -EPROTO); body->oa.o_flags = OBD_FL_DELORPHAN; body->oa.o_valid = OBD_MD_FLFLAGS | OBD_MD_FLGROUP; fid_to_ostid(&d->opd_last_used_fid, &body->oa.o_oi); ptlrpc_request_set_replen(req); /* Don't resend the delorphan req */ req->rq_no_resend = req->rq_no_delay = 1; rc = ptlrpc_queue_wait(req); if (rc) { update_status = 1; GOTO(out, rc); } body = req_capsule_server_get(&req->rq_pill, &RMF_OST_BODY); if (body == NULL) GOTO(out, rc = -EPROTO); /* * OST provides us with id new pool starts from in body->oa.o_id */ ostid_to_fid(last_fid, &body->oa.o_oi, d->opd_index); spin_lock(&d->opd_pre_lock); diff = lu_fid_diff(&d->opd_last_used_fid, last_fid); if (diff > 0) { d->opd_pre_grow_count = OST_MIN_PRECREATE + diff; d->opd_pre_last_created_fid = d->opd_last_used_fid; } else { d->opd_pre_grow_count = OST_MIN_PRECREATE; d->opd_pre_last_created_fid = *last_fid; } /* * This empties the pre-creation pool and effectively blocks any new * reservations. */ LASSERT(fid_oid(&d->opd_pre_last_created_fid) <= LUSTRE_DATA_SEQ_MAX_WIDTH); d->opd_pre_used_fid = d->opd_pre_last_created_fid; d->opd_pre_grow_slow = 0; spin_unlock(&d->opd_pre_lock); CDEBUG(D_HA, "%s: Got last_id "DFID" from OST, last_created "DFID "last_used is "DFID"\n", d->opd_obd->obd_name, PFID(last_fid), PFID(&d->opd_pre_last_created_fid), PFID(&d->opd_last_used_fid)); out: if (req) ptlrpc_req_finished(req); spin_lock(&d->opd_pre_lock); d->opd_pre_recovering = 0; spin_unlock(&d->opd_pre_lock); /* * If rc is zero, the pre-creation window should have been emptied. * Since waking up the herd would be useless without pre-created * objects, we defer the signal to osp_precreate_send() in that case. */ if (rc != 0) { if (update_status) { CERROR("%s: cannot cleanup orphans: rc = %d\n", d->opd_obd->obd_name, rc); /* we can't proceed from here, OST seem to * be in a bad shape, better to wait for * a new instance of the server and repeat * from the beginning. notify possible waiters * this OSP isn't quite functional yet */ osp_pre_update_status(d, rc); } else { wake_up(&d->opd_pre_user_waitq); } } RETURN(rc); }
static int osp_precreate_send(const struct lu_env *env, struct osp_device *d) { struct osp_thread_info *oti = osp_env_info(env); struct ptlrpc_request *req; struct obd_import *imp; struct ost_body *body; int rc, grow, diff; struct lu_fid *fid = &oti->osi_fid; ENTRY; /* don't precreate new objects till OST healthy and has free space */ if (unlikely(d->opd_pre_status)) { CDEBUG(D_INFO, "%s: don't send new precreate: rc = %d\n", d->opd_obd->obd_name, d->opd_pre_status); RETURN(0); } /* * if not connection/initialization is compeleted, ignore */ imp = d->opd_obd->u.cli.cl_import; LASSERT(imp); req = ptlrpc_request_alloc(imp, &RQF_OST_CREATE); if (req == NULL) RETURN(-ENOMEM); req->rq_request_portal = OST_CREATE_PORTAL; /* we should not resend create request - anyway we will have delorphan * and kill these objects */ req->rq_no_delay = req->rq_no_resend = 1; rc = ptlrpc_request_pack(req, LUSTRE_OST_VERSION, OST_CREATE); if (rc) { ptlrpc_request_free(req); RETURN(rc); } spin_lock(&d->opd_pre_lock); if (d->opd_pre_grow_count > d->opd_pre_max_grow_count / 2) d->opd_pre_grow_count = d->opd_pre_max_grow_count / 2; grow = d->opd_pre_grow_count; spin_unlock(&d->opd_pre_lock); body = req_capsule_client_get(&req->rq_pill, &RMF_OST_BODY); LASSERT(body); *fid = d->opd_pre_last_created_fid; rc = osp_precreate_fids(env, d, fid, &grow); if (rc == 1) { /* Current seq has been used up*/ if (!osp_is_fid_client(d)) { osp_pre_update_status(d, -ENOSPC); rc = -ENOSPC; } wake_up(&d->opd_pre_waitq); GOTO(out_req, rc); } if (!osp_is_fid_client(d)) { /* Non-FID client will always send seq 0 because of * compatiblity */ LASSERTF(fid_is_idif(fid), "Invalid fid "DFID"\n", PFID(fid)); fid->f_seq = 0; } fid_to_ostid(fid, &body->oa.o_oi); body->oa.o_valid = OBD_MD_FLGROUP; ptlrpc_request_set_replen(req); rc = ptlrpc_queue_wait(req); if (rc) { CERROR("%s: can't precreate: rc = %d\n", d->opd_obd->obd_name, rc); GOTO(out_req, rc); } LASSERT(req->rq_transno == 0); body = req_capsule_server_get(&req->rq_pill, &RMF_OST_BODY); if (body == NULL) GOTO(out_req, rc = -EPROTO); ostid_to_fid(fid, &body->oa.o_oi, d->opd_index); LASSERTF(lu_fid_diff(fid, &d->opd_pre_used_fid) > 0, "reply fid "DFID" pre used fid "DFID"\n", PFID(fid), PFID(&d->opd_pre_used_fid)); diff = lu_fid_diff(fid, &d->opd_pre_last_created_fid); spin_lock(&d->opd_pre_lock); if (diff < grow) { /* the OST has not managed to create all the * objects we asked for */ d->opd_pre_grow_count = max(diff, OST_MIN_PRECREATE); d->opd_pre_grow_slow = 1; } else { /* the OST is able to keep up with the work, * we could consider increasing grow_count * next time if needed */ d->opd_pre_grow_slow = 0; } d->opd_pre_last_created_fid = *fid; spin_unlock(&d->opd_pre_lock); CDEBUG(D_HA, "%s: current precreated pool: "DFID"-"DFID"\n", d->opd_obd->obd_name, PFID(&d->opd_pre_used_fid), PFID(&d->opd_pre_last_created_fid)); out_req: /* now we can wakeup all users awaiting for objects */ osp_pre_update_status(d, rc); wake_up(&d->opd_pre_user_waitq); ptlrpc_req_finished(req); RETURN(rc); }