/** * Prepare buffers for write request processing. * * This function converts remote buffers from client to local buffers * and prepares the latter. If there is recovery in progress and required * object is missing then it can be re-created before write. * * \param[in] env execution environment * \param[in] exp OBD export of client * \param[in] ofd OFD device * \param[in] fid FID of object * \param[in] la object attributes * \param[in] oa OBDO structure from client * \param[in] objcount always 1 * \param[in] obj object data * \param[in] rnb remote buffers * \param[in] nr_local number of local buffers * \param[in] lnb local buffers * \param[in] jobid job ID name * * \retval 0 on successful prepare * \retval negative value on error */ static int ofd_preprw_write(const struct lu_env *env, struct obd_export *exp, struct ofd_device *ofd, const struct lu_fid *fid, struct lu_attr *la, struct obdo *oa, int objcount, struct obd_ioobj *obj, struct niobuf_remote *rnb, int *nr_local, struct niobuf_local *lnb, char *jobid) { struct ofd_object *fo; int i, j, k, rc = 0, tot_bytes = 0; ENTRY; LASSERT(env != NULL); LASSERT(objcount == 1); if (unlikely(exp->exp_obd->obd_recovering)) { u64 seq = fid_seq(fid); u64 oid = fid_oid(fid); struct ofd_seq *oseq; oseq = ofd_seq_load(env, ofd, seq); if (IS_ERR(oseq)) { CERROR("%s: Can't find FID Sequence "LPX64": rc = %d\n", ofd_name(ofd), seq, (int)PTR_ERR(oseq)); GOTO(out, rc = -EINVAL); } if (oid > ofd_seq_last_oid(oseq)) { int sync = 0; int diff; mutex_lock(&oseq->os_create_lock); diff = oid - ofd_seq_last_oid(oseq); /* Do sync create if the seq is about to used up */ if (fid_seq_is_idif(seq) || fid_seq_is_mdt0(seq)) { if (unlikely(oid >= IDIF_MAX_OID - 1)) sync = 1; } else if (fid_seq_is_norm(seq)) { if (unlikely(oid >= LUSTRE_DATA_SEQ_MAX_WIDTH - 1)) sync = 1; } else { CERROR("%s : invalid o_seq "DOSTID"\n", ofd_name(ofd), POSTID(&oa->o_oi)); mutex_unlock(&oseq->os_create_lock); ofd_seq_put(env, oseq); GOTO(out, rc = -EINVAL); } while (diff > 0) { u64 next_id = ofd_seq_last_oid(oseq) + 1; int count = ofd_precreate_batch(ofd, diff); rc = ofd_precreate_objects(env, ofd, next_id, oseq, count, sync); if (rc < 0) { mutex_unlock(&oseq->os_create_lock); ofd_seq_put(env, oseq); GOTO(out, rc); } diff -= rc; } mutex_unlock(&oseq->os_create_lock); } ofd_seq_put(env, oseq); } fo = ofd_object_find(env, ofd, fid); if (IS_ERR(fo)) GOTO(out, rc = PTR_ERR(fo)); LASSERT(fo != NULL); ofd_read_lock(env, fo); if (!ofd_object_exists(fo)) { CERROR("%s: BRW to missing obj "DOSTID"\n", exp->exp_obd->obd_name, POSTID(&obj->ioo_oid)); ofd_read_unlock(env, fo); ofd_object_put(env, fo); GOTO(out, rc = -ENOENT); } if (ofd->ofd_lfsck_verify_pfid && oa->o_valid & OBD_MD_FLFID) { rc = ofd_verify_ff(env, fo, oa); if (rc != 0) { ofd_read_unlock(env, fo); ofd_object_put(env, fo); GOTO(out, rc); } } /* Process incoming grant info, set OBD_BRW_GRANTED flag and grant some * space back if possible */ ofd_grant_prepare_write(env, exp, oa, rnb, obj->ioo_bufcnt); /* parse remote buffers to local buffers and prepare the latter */ *nr_local = 0; for (i = 0, j = 0; i < obj->ioo_bufcnt; i++) { rc = dt_bufs_get(env, ofd_object_child(fo), rnb + i, lnb + j, 1); if (unlikely(rc < 0)) GOTO(err, rc); LASSERT(rc <= PTLRPC_MAX_BRW_PAGES); /* correct index for local buffers to continue with */ for (k = 0; k < rc; k++) { lnb[j+k].lnb_flags = rnb[i].rnb_flags; if (!(rnb[i].rnb_flags & OBD_BRW_GRANTED)) lnb[j+k].lnb_rc = -ENOSPC; } j += rc; *nr_local += rc; LASSERT(j <= PTLRPC_MAX_BRW_PAGES); tot_bytes += rnb[i].rnb_len; } LASSERT(*nr_local > 0 && *nr_local <= PTLRPC_MAX_BRW_PAGES); rc = dt_write_prep(env, ofd_object_child(fo), lnb, *nr_local); if (unlikely(rc != 0)) GOTO(err, rc); ofd_counter_incr(exp, LPROC_OFD_STATS_WRITE, jobid, tot_bytes); RETURN(0); err: dt_bufs_put(env, ofd_object_child(fo), lnb, *nr_local); ofd_read_unlock(env, fo); ofd_object_put(env, fo); /* ofd_grant_prepare_write() was called, so we must commit */ ofd_grant_commit(exp, oa->o_grant_used, rc); out: /* let's still process incoming grant information packed in the oa, * but without enforcing grant since we won't proceed with the write. * Just like a read request actually. */ ofd_grant_prepare_read(env, exp, oa); return rc; }
/** * Prepare bulk IO requests for processing. * * This function does initial checks of IO and calls corresponding * functions for read/write processing. * * \param[in] env execution environment * \param[in] cmd IO type (read/write) * \param[in] exp OBD export of client * \param[in] oa OBDO structure from request * \param[in] objcount always 1 * \param[in] obj object data * \param[in] rnb remote buffers * \param[in] nr_local number of local buffers * \param[in] lnb local buffers * * \retval 0 on successful prepare * \retval negative value on error */ int ofd_preprw(const struct lu_env *env, int cmd, struct obd_export *exp, struct obdo *oa, int objcount, struct obd_ioobj *obj, struct niobuf_remote *rnb, int *nr_local, struct niobuf_local *lnb) { struct tgt_session_info *tsi = tgt_ses_info(env); struct ofd_device *ofd = ofd_exp(exp); struct ofd_thread_info *info; char *jobid; const struct lu_fid *fid = &oa->o_oi.oi_fid; int rc = 0; if (*nr_local > PTLRPC_MAX_BRW_PAGES) { CERROR("%s: bulk has too many pages %d, which exceeds the" "maximum pages per RPC of %d\n", exp->exp_obd->obd_name, *nr_local, PTLRPC_MAX_BRW_PAGES); RETURN(-EPROTO); } if (tgt_ses_req(tsi) == NULL) { /* echo client case */ info = ofd_info_init(env, exp); jobid = NULL; } else { info = tsi2ofd_info(tsi); jobid = tsi->tsi_jobid; } LASSERT(oa != NULL); if (OBD_FAIL_CHECK(OBD_FAIL_SRV_ENOENT)) { struct ofd_seq *oseq; oseq = ofd_seq_load(env, ofd, ostid_seq(&oa->o_oi)); if (IS_ERR(oseq)) { CERROR("%s: Can not find seq for "DOSTID ": rc = %ld\n", ofd_name(ofd), POSTID(&oa->o_oi), PTR_ERR(oseq)); RETURN(-EINVAL); } if (oseq->os_destroys_in_progress == 0) { /* don't fail lookups for orphan recovery, it causes * later LBUGs when objects still exist during * precreate */ ofd_seq_put(env, oseq); RETURN(-ENOENT); } ofd_seq_put(env, oseq); } LASSERT(objcount == 1); LASSERT(obj->ioo_bufcnt > 0); if (cmd == OBD_BRW_WRITE) { la_from_obdo(&info->fti_attr, oa, OBD_MD_FLGETATTR); rc = ofd_preprw_write(env, exp, ofd, fid, &info->fti_attr, oa, objcount, obj, rnb, nr_local, lnb, jobid); } else if (cmd == OBD_BRW_READ) { ofd_grant_prepare_read(env, exp, oa); rc = ofd_preprw_read(env, exp, ofd, fid, &info->fti_attr, oa, obj->ioo_bufcnt, rnb, nr_local, lnb, jobid); obdo_from_la(oa, &info->fti_attr, LA_ATIME); } else { CERROR("%s: wrong cmd %d received!\n", exp->exp_obd->obd_name, cmd); rc = -EPROTO; } RETURN(rc); }
/** * Implementation of ldlm_valblock_ops::lvbo_init for OFD. * * This function allocates and initializes new LVB data for the given * LDLM resource if it is not allocated yet. New LVB is filled with attributes * of the object associated with that resource. Function does nothing if LVB * for the given LDLM resource is allocated already. * * Called with res->lr_lvb_sem held. * * \param[in] lock LDLM lock on resource * * \retval 0 on successful setup * \retval negative value on error */ static int ofd_lvbo_init(const struct lu_env *env, struct ldlm_resource *res) { struct ost_lvb *lvb; struct ofd_device *ofd; struct ofd_object *fo; struct ofd_thread_info *info; struct lu_env _env; int rc = 0; ENTRY; LASSERT(res); LASSERT(mutex_is_locked(&res->lr_lvb_mutex)); if (res->lr_lvb_data != NULL) RETURN(0); ofd = ldlm_res_to_ns(res)->ns_lvbp; LASSERT(ofd != NULL); if (OBD_FAIL_CHECK(OBD_FAIL_LDLM_OST_LVB)) RETURN(-ENOMEM); if (!env) { rc = lu_env_init(&_env, LCT_DT_THREAD); if (rc) RETURN(rc); env = &_env; } OBD_ALLOC_PTR(lvb); if (lvb == NULL) GOTO(out, rc = -ENOMEM); info = ofd_info(env); res->lr_lvb_data = lvb; res->lr_lvb_len = sizeof(*lvb); ost_fid_from_resid(&info->fti_fid, &res->lr_name, ofd->ofd_lut.lut_lsd.lsd_osd_index); fo = ofd_object_find(env, ofd, &info->fti_fid); if (IS_ERR(fo)) GOTO(out_lvb, rc = PTR_ERR(fo)); rc = ofd_attr_get(env, fo, &info->fti_attr); if (rc) { struct ofd_seq *oseq; __u64 seq; /* Object could be recreated during the first * CLEANUP_ORPHAN request. */ if (rc == -ENOENT) { seq = fid_seq(&info->fti_fid); oseq = ofd_seq_load(env, ofd, fid_seq_is_idif(seq) ? FID_SEQ_OST_MDT0 : seq); if (!IS_ERR_OR_NULL(oseq)) { if (!oseq->os_last_id_synced) rc = -EAGAIN; ofd_seq_put(env, oseq); } } GOTO(out_obj, rc); } lvb->lvb_size = info->fti_attr.la_size; lvb->lvb_blocks = info->fti_attr.la_blocks; lvb->lvb_mtime = info->fti_attr.la_mtime; lvb->lvb_atime = info->fti_attr.la_atime; lvb->lvb_ctime = info->fti_attr.la_ctime; CDEBUG(D_DLMTRACE, "res: "DFID" initial lvb size: %llu, " "mtime: %#llx, blocks: %#llx\n", PFID(&info->fti_fid), lvb->lvb_size, lvb->lvb_mtime, lvb->lvb_blocks); info->fti_attr.la_valid = 0; EXIT; out_obj: ofd_object_put(env, fo); out_lvb: if (rc != 0) OST_LVB_SET_ERR(lvb->lvb_blocks, rc); out: /* Don't free lvb data on lookup error */ if (env && env == &_env) lu_env_fini(&_env); return rc; }