/** * Implementation of obd_ops::o_get_info. * * This function is not called from request handler, it is only used by * direct call from nrs_orr_range_fill_physical() in ptlrpc, see LU-3239. * * \see ofd_get_info_hdl() for request handler function. * * \param[in] env execution environment * \param[in] exp OBD export of OFD device * \param[in] keylen length of \a key * \param[in] key key name * \param[out] vallen length of key value * \param[out] val the key value to return * \param[in] lsm not used in OFD * * \retval 0 if successful * \retval negative value on error */ static int ofd_get_info(const struct lu_env *env, struct obd_export *exp, __u32 keylen, void *key, __u32 *vallen, void *val, struct lov_stripe_md *lsm) { struct ofd_thread_info *info; struct ofd_device *ofd; struct ll_fiemap_info_key *fm_key = key; struct ll_user_fiemap *fiemap = val; int rc = 0; ENTRY; if (exp->exp_obd == NULL) { CDEBUG(D_IOCTL, "invalid client export %p\n", exp); RETURN(-EINVAL); } ofd = ofd_exp(exp); if (KEY_IS(KEY_FIEMAP)) { info = ofd_info_init(env, exp); rc = ostid_to_fid(&info->fti_fid, &fm_key->oa.o_oi, ofd->ofd_lut.lut_lsd.lsd_osd_index); if (rc != 0) RETURN(rc); rc = ofd_fiemap_get(env, ofd, &info->fti_fid, fiemap); } else { CERROR("%s: not supported key %s\n", ofd_name(ofd), (char*)key); rc = -EOPNOTSUPP; } RETURN(rc); }
/** * Implementation of obd_ops::o_postrecov. * * This function is called from target_finish_recovery() upon recovery * completion. * * \param[in] obd OBD device of OFD * * \retval 0 if successful * \retval negative value on error */ static int ofd_obd_postrecov(struct obd_device *obd) { struct lu_env env; struct lu_device *ldev = obd->obd_lu_dev; int rc; ENTRY; rc = lu_env_init(&env, LCT_DT_THREAD); if (rc) RETURN(rc); ofd_info_init(&env, obd->obd_self_export); rc = ofd_postrecov(&env, ofd_dev(ldev)); lu_env_fini(&env); 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] res LDLM resource * * \retval 0 on successful setup * \retval negative value on error */ static int ofd_lvbo_init(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); rc = lu_env_init(&env, LCT_DT_THREAD); if (rc) RETURN(rc); OBD_ALLOC_PTR(lvb); if (lvb == NULL) GOTO(out_env, rc = -ENOMEM); res->lr_lvb_data = lvb; res->lr_lvb_len = sizeof(*lvb); info = ofd_info_init(&env, NULL); 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) 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: "LPU64", " "mtime: "LPX64", blocks: "LPX64"\n", PFID(&info->fti_fid), lvb->lvb_size, lvb->lvb_mtime, lvb->lvb_blocks); EXIT; out_obj: ofd_object_put(&env, fo); out_lvb: if (rc != 0) OST_LVB_SET_ERR(lvb->lvb_blocks, rc); out_env: lu_env_fini(&env); /* Don't free lvb data on lookup error */ return rc; }
/** * Implementation of ldlm_valblock_ops::lvbo_update for OFD. * * When a client generates a glimpse enqueue, it wants to get the current * file size and updated attributes for a stat() type operation, but these * attributes may be writeback cached on another client. The client with * the DLM extent lock at the highest offset is asked for its current * attributes via a glimpse callback on its extent lock, on the assumption * that it has the highest file size and the newest timestamps. The timestamps * are guaranteed to be correct if there is only a single writer on the file, * but may be slightly inaccurate if there are multiple concurrent writers on * the same object. In order to avoid race conditions between the glimpse AST * and the client cancelling the lock, ofd_lvbo_update() also updates * the attributes from the local object. If the last client hasn't done any * writes yet, or has already written its data and cancelled its lock before * it processed the glimpse, then the local inode will have more uptodate * information. * * This is called in two ways: * \a req != NULL : called by the DLM itself after a glimpse callback * \a req == NULL : called by the OFD after a disk write * * \param[in] res LDLM resource * \param[in] req PTLRPC request * \param[in] increase_only don't allow LVB values to decrease * * \retval 0 on successful setup * \retval negative value on error */ static int ofd_lvbo_update(struct ldlm_resource *res, struct ptlrpc_request *req, int increase_only) { struct ofd_device *ofd; struct ofd_object *fo; struct ofd_thread_info *info; struct ost_lvb *lvb; struct lu_env env; int rc = 0; ENTRY; LASSERT(res != NULL); ofd = ldlm_res_to_ns(res)->ns_lvbp; LASSERT(ofd != NULL); rc = lu_env_init(&env, LCT_DT_THREAD); if (rc) RETURN(rc); info = ofd_info_init(&env, NULL); fid_extract_from_res_name(&info->fti_fid, &res->lr_name); lvb = res->lr_lvb_data; if (lvb == NULL) { CERROR("%s: no LVB data for "DFID"\n", ofd_name(ofd), PFID(&info->fti_fid)); GOTO(out_env, rc = 0); } /* Update the LVB from the network message */ if (req != NULL) { struct ost_lvb *rpc_lvb; bool lvb_type; if (req->rq_import != NULL) lvb_type = imp_connect_lvb_type(req->rq_import); else lvb_type = exp_connect_lvb_type(req->rq_export); if (!lvb_type) { struct ost_lvb_v1 *lvb_v1; lvb_v1 = req_capsule_server_swab_get(&req->rq_pill, &RMF_DLM_LVB, lustre_swab_ost_lvb_v1); if (lvb_v1 == NULL) goto disk_update; rpc_lvb = &info->fti_lvb; memcpy(rpc_lvb, lvb_v1, sizeof *lvb_v1); rpc_lvb->lvb_mtime_ns = 0; rpc_lvb->lvb_atime_ns = 0; rpc_lvb->lvb_ctime_ns = 0; } else { rpc_lvb = req_capsule_server_swab_get(&req->rq_pill, &RMF_DLM_LVB, lustre_swab_ost_lvb); if (rpc_lvb == NULL) goto disk_update; } lock_res(res); if (rpc_lvb->lvb_size > lvb->lvb_size || !increase_only) { CDEBUG(D_DLMTRACE, "res: "DFID" updating lvb size: " LPU64" -> "LPU64"\n", PFID(&info->fti_fid), lvb->lvb_size, rpc_lvb->lvb_size); lvb->lvb_size = rpc_lvb->lvb_size; } if (rpc_lvb->lvb_mtime > lvb->lvb_mtime || !increase_only) { CDEBUG(D_DLMTRACE, "res: "DFID" updating lvb mtime: " LPU64" -> "LPU64"\n", PFID(&info->fti_fid), lvb->lvb_mtime, rpc_lvb->lvb_mtime); lvb->lvb_mtime = rpc_lvb->lvb_mtime; } if (rpc_lvb->lvb_atime > lvb->lvb_atime || !increase_only) { CDEBUG(D_DLMTRACE, "res: "DFID" updating lvb atime: " LPU64" -> "LPU64"\n", PFID(&info->fti_fid), lvb->lvb_atime, rpc_lvb->lvb_atime); lvb->lvb_atime = rpc_lvb->lvb_atime; } if (rpc_lvb->lvb_ctime > lvb->lvb_ctime || !increase_only) { CDEBUG(D_DLMTRACE, "res: "DFID" updating lvb ctime: " LPU64" -> "LPU64"\n", PFID(&info->fti_fid), lvb->lvb_ctime, rpc_lvb->lvb_ctime); lvb->lvb_ctime = rpc_lvb->lvb_ctime; } if (rpc_lvb->lvb_blocks > lvb->lvb_blocks || !increase_only) { CDEBUG(D_DLMTRACE, "res: "DFID" updating lvb blocks: " LPU64" -> "LPU64"\n", PFID(&info->fti_fid), lvb->lvb_blocks, rpc_lvb->lvb_blocks); lvb->lvb_blocks = rpc_lvb->lvb_blocks; } unlock_res(res); } disk_update: /* Update the LVB from the disk inode */ 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_env, rc = PTR_ERR(fo)); rc = ofd_attr_get(&env, fo, &info->fti_attr); if (rc) GOTO(out_obj, rc); lock_res(res); if (info->fti_attr.la_size > lvb->lvb_size || !increase_only) { CDEBUG(D_DLMTRACE, "res: "DFID" updating lvb size from disk: " LPU64" -> %llu\n", PFID(&info->fti_fid), lvb->lvb_size, info->fti_attr.la_size); lvb->lvb_size = info->fti_attr.la_size; } if (info->fti_attr.la_mtime >lvb->lvb_mtime || !increase_only) { CDEBUG(D_DLMTRACE, "res: "DFID" updating lvb mtime from disk: " LPU64" -> "LPU64"\n", PFID(&info->fti_fid), lvb->lvb_mtime, info->fti_attr.la_mtime); lvb->lvb_mtime = info->fti_attr.la_mtime; } if (info->fti_attr.la_atime >lvb->lvb_atime || !increase_only) { CDEBUG(D_DLMTRACE, "res: "DFID" updating lvb atime from disk: " LPU64" -> "LPU64"\n", PFID(&info->fti_fid), lvb->lvb_atime, info->fti_attr.la_atime); lvb->lvb_atime = info->fti_attr.la_atime; } if (info->fti_attr.la_ctime >lvb->lvb_ctime || !increase_only) { CDEBUG(D_DLMTRACE, "res: "DFID" updating lvb ctime from disk: " LPU64" -> "LPU64"\n", PFID(&info->fti_fid), lvb->lvb_ctime, info->fti_attr.la_ctime); lvb->lvb_ctime = info->fti_attr.la_ctime; } if (info->fti_attr.la_blocks > lvb->lvb_blocks || !increase_only) { CDEBUG(D_DLMTRACE, "res: "DFID" updating lvb blocks from disk: " LPU64" -> %llu\n", PFID(&info->fti_fid), lvb->lvb_blocks, (unsigned long long)info->fti_attr.la_blocks); lvb->lvb_blocks = info->fti_attr.la_blocks; } unlock_res(res); out_obj: ofd_object_put(&env, fo); out_env: lu_env_fini(&env); 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); }