static int osc_io_ladvise_start(const struct lu_env *env, const struct cl_io_slice *slice) { int result = 0; struct cl_io *io = slice->cis_io; struct osc_io *oio = cl2osc_io(env, slice); struct cl_object *obj = slice->cis_obj; struct lov_oinfo *loi = cl2osc(obj)->oo_oinfo; struct cl_ladvise_io *lio = &io->u.ci_ladvise; struct obdo *oa = &oio->oi_oa; struct osc_async_cbargs *cbargs = &oio->oi_cbarg; struct lu_ladvise *ladvise; struct ladvise_hdr *ladvise_hdr; int buf_size; int num_advise = 1; ENTRY; /* TODO: add multiple ladvise support in CLIO */ buf_size = offsetof(typeof(*ladvise_hdr), lah_advise[num_advise]); if (osc_env_info(env)->oti_ladvise_buf.lb_len < buf_size) lu_buf_realloc(&osc_env_info(env)->oti_ladvise_buf, buf_size); ladvise_hdr = osc_env_info(env)->oti_ladvise_buf.lb_buf; if (ladvise_hdr == NULL) RETURN(-ENOMEM); memset(ladvise_hdr, 0, buf_size); ladvise_hdr->lah_magic = LADVISE_MAGIC; ladvise_hdr->lah_count = num_advise; ladvise_hdr->lah_flags = lio->li_flags; memset(oa, 0, sizeof(*oa)); oa->o_oi = loi->loi_oi; oa->o_valid = OBD_MD_FLID; obdo_set_parent_fid(oa, lio->li_fid); ladvise = ladvise_hdr->lah_advise; ladvise->lla_start = lio->li_start; ladvise->lla_end = lio->li_end; ladvise->lla_advice = lio->li_advice; if (lio->li_flags & LF_ASYNC) { result = osc_ladvise_base(osc_export(cl2osc(obj)), oa, ladvise_hdr, NULL, NULL, NULL); } else { init_completion(&cbargs->opc_sync); result = osc_ladvise_base(osc_export(cl2osc(obj)), oa, ladvise_hdr, osc_async_upcall, cbargs, PTLRPCD_SET); cbargs->opc_rpc_sent = result == 0; } RETURN(result); }
static int osc_fsync_ost(const struct lu_env *env, struct osc_object *obj, struct cl_fsync_io *fio) { struct osc_io *oio = osc_env_io(env); struct obdo *oa = &oio->oi_oa; struct obd_info *oinfo = &oio->oi_info; struct lov_oinfo *loi = obj->oo_oinfo; struct osc_async_cbargs *cbargs = &oio->oi_cbarg; int rc = 0; memset(oa, 0, sizeof(*oa)); oa->o_oi = loi->loi_oi; oa->o_valid = OBD_MD_FLID | OBD_MD_FLGROUP; /* reload size abd blocks for start and end of sync range */ oa->o_size = fio->fi_start; oa->o_blocks = fio->fi_end; oa->o_valid |= OBD_MD_FLSIZE | OBD_MD_FLBLOCKS; obdo_set_parent_fid(oa, fio->fi_fid); memset(oinfo, 0, sizeof(*oinfo)); oinfo->oi_oa = oa; oinfo->oi_capa = fio->fi_capa; init_completion(&cbargs->opc_sync); rc = osc_sync_base(osc_export(obj), oinfo, osc_async_upcall, cbargs, PTLRPCD_SET); return rc; }
static int osc_io_commit_write(const struct lu_env *env, const struct cl_io_slice *ios, const struct cl_page_slice *slice, unsigned from, unsigned to) { struct osc_io *oio = cl2osc_io(env, ios); struct osc_page *opg = cl2osc_page(slice); struct osc_object *obj = cl2osc(opg->ops_cl.cpl_obj); struct osc_async_page *oap = &opg->ops_oap; LASSERT(to > 0); /* * XXX instead of calling osc_page_touch() here and in * osc_io_fault_start() it might be more logical to introduce * cl_page_touch() method, that generic cl_io_commit_write() and page * fault code calls. */ osc_page_touch(env, cl2osc_page(slice), to); if (!client_is_remote(osc_export(obj)) && capable(CFS_CAP_SYS_RESOURCE)) oap->oap_brw_flags |= OBD_BRW_NOQUOTA; if (oio->oi_lockless) /* see osc_io_prepare_write() for lockless io handling. */ cl_page_clip(env, slice->cpl_page, from, to); return 0; }
static int osc_object_prune(const struct lu_env *env, struct cl_object *obj) { struct osc_object *osc = cl2osc(obj); struct ldlm_res_id *resname = &osc_env_info(env)->oti_resname; /* DLM locks don't hold a reference of osc_object so we have to * clear it before the object is being destroyed. */ ostid_build_res_name(&osc->oo_oinfo->loi_oi, resname); ldlm_resource_iterate(osc_export(osc)->exp_obd->obd_namespace, resname, osc_object_ast_clear, osc); return 0; }
static int osc_io_data_version_start(const struct lu_env *env, const struct cl_io_slice *slice) { struct cl_data_version_io *dv = &slice->cis_io->u.ci_data_version; struct osc_io *oio = cl2osc_io(env, slice); struct obdo *oa = &oio->oi_oa; struct osc_async_cbargs *cbargs = &oio->oi_cbarg; struct osc_object *obj = cl2osc(slice->cis_obj); struct lov_oinfo *loi = obj->oo_oinfo; struct obd_export *exp = osc_export(obj); struct ptlrpc_request *req; struct ost_body *body; struct osc_data_version_args *dva; int rc; ENTRY; memset(oa, 0, sizeof(*oa)); oa->o_oi = loi->loi_oi; oa->o_valid = OBD_MD_FLID | OBD_MD_FLGROUP; if (dv->dv_flags & (LL_DV_RD_FLUSH | LL_DV_WR_FLUSH)) { oa->o_valid |= OBD_MD_FLFLAGS; oa->o_flags |= OBD_FL_SRVLOCK; if (dv->dv_flags & LL_DV_WR_FLUSH) oa->o_flags |= OBD_FL_FLUSH; } init_completion(&cbargs->opc_sync); req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_OST_GETATTR); if (req == NULL) RETURN(-ENOMEM); rc = ptlrpc_request_pack(req, LUSTRE_OST_VERSION, OST_GETATTR); if (rc < 0) { ptlrpc_request_free(req); RETURN(rc); } body = req_capsule_client_get(&req->rq_pill, &RMF_OST_BODY); lustre_set_wire_obdo(&req->rq_import->imp_connect_data, &body->oa, oa); ptlrpc_request_set_replen(req); req->rq_interpret_reply = osc_data_version_interpret; CLASSERT(sizeof(*dva) <= sizeof(req->rq_async_args)); dva = ptlrpc_req_async_args(req); dva->dva_oio = oio; ptlrpcd_add_req(req); RETURN(0); }
static int osc_object_prune(const struct lu_env *env, struct cl_object *obj) { struct osc_object *osc = cl2osc(obj); struct ldlm_res_id *resname = &osc_env_info(env)->oti_resname; LASSERTF(osc->oo_npages == 0, DFID "still have %lu pages, obj: %p, osc: %p\n", PFID(lu_object_fid(&obj->co_lu)), osc->oo_npages, obj, osc); /* DLM locks don't hold a reference of osc_object so we have to * clear it before the object is being destroyed. */ ostid_build_res_name(&osc->oo_oinfo->loi_oi, resname); ldlm_resource_iterate(osc_export(osc)->exp_obd->obd_namespace, resname, osc_object_ast_clear, osc); return 0; }
/** * Finds an existing lock covering a page with given index. * Copy of osc_obj_dlmlock_at_pgoff() but for DoM IBITS lock. */ struct ldlm_lock *mdc_dlmlock_at_pgoff(const struct lu_env *env, struct osc_object *obj, pgoff_t index, enum osc_dap_flags dap_flags) { struct osc_thread_info *info = osc_env_info(env); struct ldlm_res_id *resname = &info->oti_resname; union ldlm_policy_data *policy = &info->oti_policy; struct lustre_handle lockh; struct ldlm_lock *lock = NULL; enum ldlm_mode mode; __u64 flags; ENTRY; fid_build_reg_res_name(lu_object_fid(osc2lu(obj)), resname); mdc_lock_build_policy(env, policy); flags = LDLM_FL_BLOCK_GRANTED | LDLM_FL_CBPENDING; if (dap_flags & OSC_DAP_FL_TEST_LOCK) flags |= LDLM_FL_TEST_LOCK; again: /* Next, search for already existing extent locks that will cover us */ /* If we're trying to read, we also search for an existing PW lock. The * VFS and page cache already protect us locally, so lots of readers/ * writers can share a single PW lock. */ mode = mdc_dom_lock_match(env, osc_export(obj), resname, LDLM_IBITS, policy, LCK_PR | LCK_PW, &flags, obj, &lockh, dap_flags & OSC_DAP_FL_CANCELING); if (mode != 0) { lock = ldlm_handle2lock(&lockh); /* RACE: the lock is cancelled so let's try again */ if (unlikely(lock == NULL)) goto again; } RETURN(lock); }
/** * Implementation of struct cl_object_operations::coo_req_attr_set() for osc * layer. osc is responsible for struct obdo::o_id and struct obdo::o_seq * fields. */ static void osc_req_attr_set(const struct lu_env *env, struct cl_object *obj, struct cl_req_attr *attr) { struct lov_oinfo *oinfo; struct obdo *oa; struct ost_lvb *lvb; u64 flags = attr->cra_flags; oinfo = cl2osc(obj)->oo_oinfo; lvb = &oinfo->loi_lvb; oa = attr->cra_oa; if ((flags & OBD_MD_FLMTIME) != 0) { oa->o_mtime = lvb->lvb_mtime; oa->o_valid |= OBD_MD_FLMTIME; } if ((flags & OBD_MD_FLATIME) != 0) { oa->o_atime = lvb->lvb_atime; oa->o_valid |= OBD_MD_FLATIME; } if ((flags & OBD_MD_FLCTIME) != 0) { oa->o_ctime = lvb->lvb_ctime; oa->o_valid |= OBD_MD_FLCTIME; } if (flags & OBD_MD_FLGROUP) { ostid_set_seq(&oa->o_oi, ostid_seq(&oinfo->loi_oi)); oa->o_valid |= OBD_MD_FLGROUP; } if (flags & OBD_MD_FLID) { ostid_set_id(&oa->o_oi, ostid_id(&oinfo->loi_oi)); oa->o_valid |= OBD_MD_FLID; } if (flags & OBD_MD_FLHANDLE) { struct ldlm_lock *lock; struct osc_page *opg; opg = osc_cl_page_osc(attr->cra_page, cl2osc(obj)); lock = osc_dlmlock_at_pgoff(env, cl2osc(obj), osc_index(opg), OSC_DAP_FL_TEST_LOCK | OSC_DAP_FL_CANCELING); if (lock == NULL && !opg->ops_srvlock) { struct ldlm_resource *res; struct ldlm_res_id *resname; CL_PAGE_DEBUG(D_ERROR, env, attr->cra_page, "uncovered page!\n"); resname = &osc_env_info(env)->oti_resname; ostid_build_res_name(&oinfo->loi_oi, resname); res = ldlm_resource_get( osc_export(cl2osc(obj))->exp_obd->obd_namespace, NULL, resname, LDLM_EXTENT, 0); ldlm_resource_dump(D_ERROR, res); libcfs_debug_dumpstack(NULL); LBUG(); } /* check for lockless io. */ if (lock != NULL) { oa->o_handle = lock->l_remote_handle; oa->o_valid |= OBD_MD_FLHANDLE; LDLM_LOCK_PUT(lock); } } }
static int osc_object_fiemap(const struct lu_env *env, struct cl_object *obj, struct ll_fiemap_info_key *fmkey, struct fiemap *fiemap, size_t *buflen) { struct obd_export *exp = osc_export(cl2osc(obj)); struct ldlm_res_id resid; union ldlm_policy_data policy; struct lustre_handle lockh; enum ldlm_mode mode = LCK_MINMODE; struct ptlrpc_request *req; struct fiemap *reply; char *tmp; int rc; ENTRY; fmkey->lfik_oa.o_oi = cl2osc(obj)->oo_oinfo->loi_oi; if (!(fmkey->lfik_fiemap.fm_flags & FIEMAP_FLAG_SYNC)) goto skip_locking; policy.l_extent.start = fmkey->lfik_fiemap.fm_start & PAGE_MASK; if (OBD_OBJECT_EOF - fmkey->lfik_fiemap.fm_length <= fmkey->lfik_fiemap.fm_start + PAGE_SIZE - 1) policy.l_extent.end = OBD_OBJECT_EOF; else policy.l_extent.end = (fmkey->lfik_fiemap.fm_start + fmkey->lfik_fiemap.fm_length + PAGE_SIZE - 1) & PAGE_MASK; ostid_build_res_name(&fmkey->lfik_oa.o_oi, &resid); mode = ldlm_lock_match(exp->exp_obd->obd_namespace, LDLM_FL_BLOCK_GRANTED | LDLM_FL_LVB_READY, &resid, LDLM_EXTENT, &policy, LCK_PR | LCK_PW, &lockh, 0); if (mode) { /* lock is cached on client */ if (mode != LCK_PR) { ldlm_lock_addref(&lockh, LCK_PR); ldlm_lock_decref(&lockh, LCK_PW); } } else { /* no cached lock, needs acquire lock on server side */ fmkey->lfik_oa.o_valid |= OBD_MD_FLFLAGS; fmkey->lfik_oa.o_flags |= OBD_FL_SRVLOCK; } skip_locking: req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_OST_GET_INFO_FIEMAP); if (req == NULL) GOTO(drop_lock, rc = -ENOMEM); req_capsule_set_size(&req->rq_pill, &RMF_FIEMAP_KEY, RCL_CLIENT, sizeof(*fmkey)); req_capsule_set_size(&req->rq_pill, &RMF_FIEMAP_VAL, RCL_CLIENT, *buflen); req_capsule_set_size(&req->rq_pill, &RMF_FIEMAP_VAL, RCL_SERVER, *buflen); rc = ptlrpc_request_pack(req, LUSTRE_OST_VERSION, OST_GET_INFO); if (rc != 0) { ptlrpc_request_free(req); GOTO(drop_lock, rc); } tmp = req_capsule_client_get(&req->rq_pill, &RMF_FIEMAP_KEY); memcpy(tmp, fmkey, sizeof(*fmkey)); tmp = req_capsule_client_get(&req->rq_pill, &RMF_FIEMAP_VAL); memcpy(tmp, fiemap, *buflen); ptlrpc_request_set_replen(req); rc = ptlrpc_queue_wait(req); if (rc != 0) GOTO(fini_req, rc); reply = req_capsule_server_get(&req->rq_pill, &RMF_FIEMAP_VAL); if (reply == NULL) GOTO(fini_req, rc = -EPROTO); memcpy(fiemap, reply, *buflen); fini_req: ptlrpc_req_finished(req); drop_lock: if (mode) ldlm_lock_decref(&lockh, LCK_PR); RETURN(rc); }
static int osc_io_setattr_start(const struct lu_env *env, const struct cl_io_slice *slice) { struct cl_io *io = slice->cis_io; struct osc_io *oio = cl2osc_io(env, slice); struct cl_object *obj = slice->cis_obj; struct lov_oinfo *loi = cl2osc(obj)->oo_oinfo; struct cl_attr *attr = &osc_env_info(env)->oti_attr; struct obdo *oa = &oio->oi_oa; struct osc_async_cbargs *cbargs = &oio->oi_cbarg; __u64 size = io->u.ci_setattr.sa_attr.lvb_size; unsigned int ia_valid = io->u.ci_setattr.sa_valid; int result = 0; struct obd_info oinfo = { { { 0 } } }; /* truncate cache dirty pages first */ if (cl_io_is_trunc(io)) result = osc_cache_truncate_start(env, oio, cl2osc(obj), size); if (result == 0 && oio->oi_lockless == 0) { cl_object_attr_lock(obj); result = cl_object_attr_get(env, obj, attr); if (result == 0) { struct ost_lvb *lvb = &io->u.ci_setattr.sa_attr; unsigned int cl_valid = 0; if (ia_valid & ATTR_SIZE) { attr->cat_size = attr->cat_kms = size; cl_valid = (CAT_SIZE | CAT_KMS); } if (ia_valid & ATTR_MTIME_SET) { attr->cat_mtime = lvb->lvb_mtime; cl_valid |= CAT_MTIME; } if (ia_valid & ATTR_ATIME_SET) { attr->cat_atime = lvb->lvb_atime; cl_valid |= CAT_ATIME; } if (ia_valid & ATTR_CTIME_SET) { attr->cat_ctime = lvb->lvb_ctime; cl_valid |= CAT_CTIME; } result = cl_object_attr_set(env, obj, attr, cl_valid); } cl_object_attr_unlock(obj); } memset(oa, 0, sizeof(*oa)); if (result == 0) { oa->o_oi = loi->loi_oi; oa->o_mtime = attr->cat_mtime; oa->o_atime = attr->cat_atime; oa->o_ctime = attr->cat_ctime; oa->o_valid = OBD_MD_FLID | OBD_MD_FLGROUP | OBD_MD_FLATIME | OBD_MD_FLCTIME | OBD_MD_FLMTIME; if (ia_valid & ATTR_SIZE) { oa->o_size = size; oa->o_blocks = OBD_OBJECT_EOF; oa->o_valid |= OBD_MD_FLSIZE | OBD_MD_FLBLOCKS; if (oio->oi_lockless) { oa->o_flags = OBD_FL_SRVLOCK; oa->o_valid |= OBD_MD_FLFLAGS; } } else { LASSERT(oio->oi_lockless == 0); } oinfo.oi_oa = oa; oinfo.oi_capa = io->u.ci_setattr.sa_capa; init_completion(&cbargs->opc_sync); if (ia_valid & ATTR_SIZE) result = osc_punch_base(osc_export(cl2osc(obj)), &oinfo, osc_async_upcall, cbargs, PTLRPCD_SET); else result = osc_setattr_async_base(osc_export(cl2osc(obj)), &oinfo, NULL, osc_async_upcall, cbargs, PTLRPCD_SET); cbargs->opc_rpc_sent = result == 0; } return result; }