/** * Implementation of the llog_operations::lop_create * * This function creates the llog according with llog_handle::lgh_obj * and llog_handle::lgh_name. * * \param[in] env execution environment * \param[in] res llog handle of the current llog * \param[in] th current transaction handle * * \retval 0 on successful create * \retval negative value on error */ static int llog_osd_create(const struct lu_env *env, struct llog_handle *res, struct thandle *th) { struct llog_thread_info *lgi = llog_info(env); struct dt_insert_rec *rec = &lgi->lgi_dt_rec; struct local_oid_storage *los; struct dt_object *o; int rc = 0; ENTRY; LASSERT(env); o = res->lgh_obj; LASSERT(o); /* llog can be already created */ if (dt_object_exists(o)) RETURN(-EEXIST); los = res->private_data; LASSERT(los); dt_write_lock(env, o, 0); if (!dt_object_exists(o)) rc = llog_osd_create_new_object(env, los, o, th); else rc = -EEXIST; dt_write_unlock(env, o); if (rc) RETURN(rc); if (res->lgh_name) { struct dt_object *llog_dir; llog_dir = llog_osd_dir_get(env, res->lgh_ctxt); if (IS_ERR(llog_dir)) RETURN(PTR_ERR(llog_dir)); logid_to_fid(&res->lgh_id, &lgi->lgi_fid); rec->rec_fid = &lgi->lgi_fid; rec->rec_type = S_IFREG; dt_read_lock(env, llog_dir, 0); rc = dt_insert(env, llog_dir, (struct dt_rec *)rec, (struct dt_key *)res->lgh_name, th, BYPASS_CAPA, 1); dt_read_unlock(env, llog_dir); lu_object_put(env, &llog_dir->do_lu); if (rc) CERROR("%s: can't create named llog %s: rc = %d\n", o->do_lu.lo_dev->ld_obd->obd_name, res->lgh_name, rc); } RETURN(rc); }
static int out_xattr_get(struct tgt_session_info *tsi) { const struct lu_env *env = tsi->tsi_env; struct tgt_thread_info *tti = tgt_th_info(env); struct object_update *update = tti->tti_u.update.tti_update; struct lu_buf *lbuf = &tti->tti_buf; struct object_update_reply *reply = tti->tti_u.update.tti_update_reply; struct dt_object *obj = tti->tti_u.update.tti_dt_object; char *name; struct object_update_result *update_result; int idx = tti->tti_u.update.tti_update_reply_index; int rc; ENTRY; if (!lu_object_exists(&obj->do_lu)) { set_bit(LU_OBJECT_HEARD_BANSHEE, &obj->do_lu.lo_header->loh_flags); RETURN(-ENOENT); } name = object_update_param_get(update, 0, NULL); if (IS_ERR(name)) { CERROR("%s: empty name for xattr get: rc = %ld\n", tgt_name(tsi->tsi_tgt), PTR_ERR(name)); RETURN(PTR_ERR(name)); } update_result = object_update_result_get(reply, 0, NULL); if (update_result == NULL) { CERROR("%s: empty name for xattr get: rc = %d\n", tgt_name(tsi->tsi_tgt), -EPROTO); RETURN(-EPROTO); } lbuf->lb_len = (int)tti->tti_u.update.tti_update->ou_result_size; lbuf->lb_buf = update_result->our_data; if (lbuf->lb_len == 0) lbuf->lb_buf = 0; dt_read_lock(env, obj, MOR_TGT_CHILD); rc = dt_xattr_get(env, obj, lbuf, name); dt_read_unlock(env, obj); if (rc < 0) lbuf->lb_len = 0; CDEBUG(D_INFO, "%s: "DFID" get xattr %s len %d\n", tgt_name(tsi->tsi_tgt), PFID(lu_object_fid(&obj->do_lu)), name, (int)lbuf->lb_len); GOTO(out, rc); out: object_update_result_insert(reply, lbuf->lb_buf, lbuf->lb_len, idx, rc); RETURN(0); }
static int out_index_lookup(struct tgt_session_info *tsi) { const struct lu_env *env = tsi->tsi_env; struct tgt_thread_info *tti = tgt_th_info(env); struct object_update *update = tti->tti_u.update.tti_update; struct dt_object *obj = tti->tti_u.update.tti_dt_object; char *name; int rc; ENTRY; if (unlikely(update->ou_result_size < sizeof(tti->tti_fid1))) return -EPROTO; if (!lu_object_exists(&obj->do_lu)) RETURN(-ENOENT); name = object_update_param_get(update, 0, NULL); if (IS_ERR(name)) { CERROR("%s: empty name for lookup: rc = %ld\n", tgt_name(tsi->tsi_tgt), PTR_ERR(name)); RETURN(PTR_ERR(name)); } dt_read_lock(env, obj, MOR_TGT_CHILD); if (!dt_try_as_dir(env, obj)) GOTO(out_unlock, rc = -ENOTDIR); rc = dt_lookup(env, obj, (struct dt_rec *)&tti->tti_fid1, (struct dt_key *)name); if (rc < 0) GOTO(out_unlock, rc); if (rc == 0) rc += 1; out_unlock: dt_read_unlock(env, obj); CDEBUG(D_INFO, "lookup "DFID" %s get "DFID" rc %d\n", PFID(lu_object_fid(&obj->do_lu)), name, PFID(&tti->tti_fid1), rc); CDEBUG(D_INFO, "%s: insert lookup reply %p index %d: rc = %d\n", tgt_name(tsi->tsi_tgt), tti->tti_u.update.tti_update_reply, 0, rc); object_update_result_insert(tti->tti_u.update.tti_update_reply, &tti->tti_fid1, sizeof(tti->tti_fid1), tti->tti_u.update.tti_update_reply_index, rc); RETURN(rc); }
static int out_index_lookup(struct tgt_session_info *tsi) { const struct lu_env *env = tsi->tsi_env; struct tgt_thread_info *tti = tgt_th_info(env); struct update *update = tti->tti_u.update.tti_update; struct dt_object *obj = tti->tti_u.update.tti_dt_object; char *name; int rc; ENTRY; if (!lu_object_exists(&obj->do_lu)) RETURN(-ENOENT); name = (char *)update_param_buf(update, 0, NULL); if (name == NULL) { CERROR("%s: empty name for lookup: rc = %d\n", tgt_name(tsi->tsi_tgt), -EPROTO); RETURN(err_serious(-EPROTO)); } dt_read_lock(env, obj, MOR_TGT_CHILD); if (!dt_try_as_dir(env, obj)) GOTO(out_unlock, rc = -ENOTDIR); rc = dt_lookup(env, obj, (struct dt_rec *)&tti->tti_fid1, (struct dt_key *)name, NULL); if (rc < 0) GOTO(out_unlock, rc); if (rc == 0) rc += 1; CDEBUG(D_INFO, "lookup "DFID" %s get "DFID" rc %d\n", PFID(lu_object_fid(&obj->do_lu)), name, PFID(&tti->tti_fid1), rc); fid_cpu_to_le(&tti->tti_fid1, &tti->tti_fid1); out_unlock: dt_read_unlock(env, obj); CDEBUG(D_INFO, "%s: insert lookup reply %p index %d: rc = %d\n", tgt_name(tsi->tsi_tgt), tti->tti_u.update.tti_update_reply, 0, rc); update_insert_reply(tti->tti_u.update.tti_update_reply, &tti->tti_fid1, sizeof(tti->tti_fid1), 0, rc); RETURN(rc); }
static int out_xattr_get(struct tgt_session_info *tsi) { const struct lu_env *env = tsi->tsi_env; struct tgt_thread_info *tti = tgt_th_info(env); struct update *update = tti->tti_u.update.tti_update; struct lu_buf *lbuf = &tti->tti_buf; struct update_reply *reply = tti->tti_u.update.tti_update_reply; struct dt_object *obj = tti->tti_u.update.tti_dt_object; char *name; void *ptr; int rc; ENTRY; name = (char *)update_param_buf(update, 0, NULL); if (name == NULL) { CERROR("%s: empty name for xattr get: rc = %d\n", tgt_name(tsi->tsi_tgt), -EPROTO); RETURN(err_serious(-EPROTO)); } ptr = update_get_buf_internal(reply, 0, NULL); LASSERT(ptr != NULL); /* The first 4 bytes(int) are used to store the result */ lbuf->lb_buf = (char *)ptr + sizeof(int); lbuf->lb_len = UPDATE_BUFFER_SIZE - sizeof(struct update_reply); dt_read_lock(env, obj, MOR_TGT_CHILD); rc = dt_xattr_get(env, obj, lbuf, name, NULL); dt_read_unlock(env, obj); if (rc < 0) { lbuf->lb_len = 0; GOTO(out, rc); } if (rc == 0) { lbuf->lb_len = 0; GOTO(out, rc = -ENOENT); } lbuf->lb_len = rc; rc = 0; CDEBUG(D_INFO, "%s: "DFID" get xattr %s len %d\n", tgt_name(tsi->tsi_tgt), PFID(lu_object_fid(&obj->do_lu)), name, (int)lbuf->lb_len); out: *(int *)ptr = rc; reply->ur_lens[0] = lbuf->lb_len + sizeof(int); RETURN(rc); }
/* * Retrieve quota settings from disk for a particular identifier. * * \param env - is the environment passed by the caller * \param obj - is the on-disk index where quota settings are stored. * \param id - is the key to be updated * \param rec - is the output record where to store quota settings. * * \retval - 0 on success, appropriate error on failure */ int lquota_disk_read(const struct lu_env *env, struct dt_object *obj, union lquota_id *id, struct dt_rec *rec) { int rc; ENTRY; LASSERT(dt_object_exists(obj)); LASSERT(obj->do_index_ops != NULL); /* lookup on-disk record from index file */ dt_read_lock(env, obj, 0); rc = dt_lookup(env, obj, rec, (struct dt_key *)&id->qid_uid); dt_read_unlock(env, obj); RETURN(rc); }
static int out_attr_get(struct tgt_session_info *tsi) { const struct lu_env *env = tsi->tsi_env; struct tgt_thread_info *tti = tgt_th_info(env); struct object_update *update = tti->tti_u.update.tti_update; struct obdo *obdo = &tti->tti_u.update.tti_obdo; struct lu_attr *la = &tti->tti_attr; struct dt_object *obj = tti->tti_u.update.tti_dt_object; int idx = tti->tti_u.update.tti_update_reply_index; int rc; ENTRY; if (unlikely(update->ou_result_size < sizeof(*obdo))) return -EPROTO; if (!lu_object_exists(&obj->do_lu)) { /* Usually, this will be called when the master MDT try * to init a remote object(see osp_object_init), so if * the object does not exist on slave, we need set BANSHEE flag, * so the object can be removed from the cache immediately */ set_bit(LU_OBJECT_HEARD_BANSHEE, &obj->do_lu.lo_header->loh_flags); RETURN(-ENOENT); } dt_read_lock(env, obj, MOR_TGT_CHILD); rc = dt_attr_get(env, obj, la); if (rc) GOTO(out_unlock, rc); obdo->o_valid = 0; obdo_from_la(obdo, la, la->la_valid); lustre_set_wire_obdo(NULL, obdo, obdo); out_unlock: dt_read_unlock(env, obj); CDEBUG(D_INFO, "%s: insert attr get reply %p index %d: rc = %d\n", tgt_name(tsi->tsi_tgt), tti->tti_u.update.tti_update_reply, 0, rc); object_update_result_insert(tti->tti_u.update.tti_update_reply, obdo, sizeof(*obdo), idx, rc); RETURN(rc); }
static int out_index_lookup(struct mdt_thread_info *info) { struct update *update = info->mti_u.update.mti_update; const struct lu_env *env = info->mti_env; struct dt_object *obj = info->mti_u.update.mti_dt_object; char *name; int rc; ENTRY; if (!lu_object_exists(&obj->do_lu)) RETURN(-ENOENT); name = (char *)update_param_buf(update, 0, NULL); if (name == NULL) { CERROR("%s: empty name for lookup: rc = %d\n", mdt_obd_name(info->mti_mdt), -EPROTO); RETURN(err_serious(-EPROTO)); } dt_read_lock(env, obj, MOR_TGT_CHILD); if (!dt_try_as_dir(env, obj)) GOTO(out_unlock, rc = -ENOTDIR); rc = dt_lookup(env, obj, (struct dt_rec *)&info->mti_tmp_fid1, (struct dt_key *)name, NULL); if (rc < 0) GOTO(out_unlock, rc); if (rc == 0) rc += 1; CDEBUG(D_INFO, "lookup "DFID" %s get "DFID" rc %d\n", PFID(lu_object_fid(&obj->do_lu)), name, PFID(&info->mti_tmp_fid1), rc); fid_cpu_to_le(&info->mti_tmp_fid1, &info->mti_tmp_fid1); out_unlock: dt_read_unlock(env, obj); update_insert_reply(info->mti_u.update.mti_update_reply, &info->mti_tmp_fid1, sizeof(info->mti_tmp_fid1), 0, rc); RETURN(rc); }
/** * Implementation of the llog_operations::lop_open * * This function opens the llog by its logid or by name, it may open also * non existent llog and assing then new id to it. * The llog_open/llog_close pair works similar to lu_object_find/put, * the object may not exist prior open. The result of open is just dt_object * in the llog header. * * \param[in] env execution environment * \param[in] handle llog handle of the current llog * \param[in] logid logid of llog to open (nameless llog) * \param[in] name name of llog to open (named llog) * \param[in] open_param * LLOG_OPEN_NEW - new llog, may not exist * LLOG_OPEN_EXIST - old llog, must exist * * \retval 0 on successful open, llog_handle::lgh_obj * contains the dt_object of the llog. * \retval negative value on error */ static int llog_osd_open(const struct lu_env *env, struct llog_handle *handle, struct llog_logid *logid, char *name, enum llog_open_param open_param) { struct llog_thread_info *lgi = llog_info(env); struct llog_ctxt *ctxt = handle->lgh_ctxt; struct dt_object *o; struct dt_device *dt; struct ls_device *ls; struct local_oid_storage *los; int rc = 0; ENTRY; LASSERT(env); LASSERT(ctxt); LASSERT(ctxt->loc_exp); LASSERT(ctxt->loc_exp->exp_obd); dt = ctxt->loc_exp->exp_obd->obd_lvfs_ctxt.dt; LASSERT(dt); ls = ls_device_get(dt); if (IS_ERR(ls)) RETURN(PTR_ERR(ls)); mutex_lock(&ls->ls_los_mutex); los = dt_los_find(ls, name != NULL ? FID_SEQ_LLOG_NAME : FID_SEQ_LLOG); mutex_unlock(&ls->ls_los_mutex); LASSERT(los); ls_device_put(env, ls); LASSERT(handle); if (logid != NULL) { logid_to_fid(logid, &lgi->lgi_fid); } else if (name) { struct dt_object *llog_dir; llog_dir = llog_osd_dir_get(env, ctxt); if (IS_ERR(llog_dir)) GOTO(out, rc = PTR_ERR(llog_dir)); dt_read_lock(env, llog_dir, 0); rc = dt_lookup_dir(env, llog_dir, name, &lgi->lgi_fid); dt_read_unlock(env, llog_dir); lu_object_put(env, &llog_dir->do_lu); if (rc == -ENOENT && open_param == LLOG_OPEN_NEW) { /* generate fid for new llog */ rc = local_object_fid_generate(env, los, &lgi->lgi_fid); } if (rc < 0) GOTO(out, rc); OBD_ALLOC(handle->lgh_name, strlen(name) + 1); if (handle->lgh_name) strcpy(handle->lgh_name, name); else GOTO(out, rc = -ENOMEM); } else { LASSERTF(open_param & LLOG_OPEN_NEW, "%#x\n", open_param); /* generate fid for new llog */ rc = local_object_fid_generate(env, los, &lgi->lgi_fid); if (rc < 0) GOTO(out, rc); } o = ls_locate(env, ls, &lgi->lgi_fid, NULL); if (IS_ERR(o)) GOTO(out_name, rc = PTR_ERR(o)); /* No new llog is expected but doesn't exist */ if (open_param != LLOG_OPEN_NEW && !dt_object_exists(o)) GOTO(out_put, rc = -ENOENT); fid_to_logid(&lgi->lgi_fid, &handle->lgh_id); handle->lgh_obj = o; handle->private_data = los; LASSERT(handle->lgh_ctxt); RETURN(rc); out_put: lu_object_put(env, &o->do_lu); out_name: if (handle->lgh_name != NULL) OBD_FREE(handle->lgh_name, strlen(name) + 1); out: dt_los_put(los); RETURN(rc); }
/** * Implementation of the llog_operations::lop_destroy * * This function destroys the llog and deletes also entry in the * llog directory in case of named llog. Llog should be opened prior that. * Destroy method is not part of external transaction and does everything * inside. * * \param[in] env execution environment * \param[in] loghandle llog handle of the current llog * * \retval 0 on successful destroy * \retval negative value on error */ static int llog_osd_destroy(const struct lu_env *env, struct llog_handle *loghandle) { struct llog_ctxt *ctxt; struct dt_object *o, *llog_dir = NULL; struct dt_device *d; struct thandle *th; char *name = NULL; int rc; ENTRY; ctxt = loghandle->lgh_ctxt; LASSERT(ctxt); o = loghandle->lgh_obj; LASSERT(o); d = lu2dt_dev(o->do_lu.lo_dev); LASSERT(d); LASSERT(d == ctxt->loc_exp->exp_obd->obd_lvfs_ctxt.dt); th = dt_trans_create(env, d); if (IS_ERR(th)) RETURN(PTR_ERR(th)); if (loghandle->lgh_name) { llog_dir = llog_osd_dir_get(env, ctxt); if (IS_ERR(llog_dir)) GOTO(out_trans, rc = PTR_ERR(llog_dir)); name = loghandle->lgh_name; rc = dt_declare_delete(env, llog_dir, (struct dt_key *)name, th); if (rc) GOTO(out_trans, rc); } dt_declare_ref_del(env, o, th); rc = dt_declare_destroy(env, o, th); if (rc) GOTO(out_trans, rc); rc = dt_trans_start_local(env, d, th); if (rc) GOTO(out_trans, rc); dt_write_lock(env, o, 0); if (dt_object_exists(o)) { if (name) { dt_read_lock(env, llog_dir, 0); rc = dt_delete(env, llog_dir, (struct dt_key *) name, th, BYPASS_CAPA); dt_read_unlock(env, llog_dir); if (rc) { CERROR("%s: can't remove llog %s: rc = %d\n", o->do_lu.lo_dev->ld_obd->obd_name, name, rc); GOTO(out_unlock, rc); } } dt_ref_del(env, o, th); rc = dt_destroy(env, o, th); if (rc) GOTO(out_unlock, rc); } out_unlock: dt_write_unlock(env, o); out_trans: dt_trans_stop(env, d, th); if (llog_dir != NULL) lu_object_put(env, &llog_dir->do_lu); RETURN(rc); }
static int llog_osd_destroy(const struct lu_env *env, struct llog_handle *loghandle) { struct llog_thread_info *lgi = llog_info(env); struct llog_ctxt *ctxt; struct dt_object *o, *llog_dir = NULL; struct dt_device *d; struct thandle *th; char *name = NULL; int rc; ENTRY; ctxt = loghandle->lgh_ctxt; LASSERT(ctxt); o = loghandle->lgh_obj; LASSERT(o); d = lu2dt_dev(o->do_lu.lo_dev); LASSERT(d); LASSERT(d == ctxt->loc_exp->exp_obd->obd_lvfs_ctxt.dt); th = dt_trans_create(env, d); if (IS_ERR(th)) RETURN(PTR_ERR(th)); if (loghandle->lgh_name) { llog_dir = llog_osd_dir_get(env, ctxt); if (IS_ERR(llog_dir)) GOTO(out_trans, rc = PTR_ERR(llog_dir)); dt_declare_ref_del(env, o, th); name = loghandle->lgh_name; rc = dt_declare_delete(env, llog_dir, (struct dt_key *)name, th); if (rc) GOTO(out_trans, rc); } dt_declare_ref_del(env, o, th); rc = dt_declare_destroy(env, o, th); if (rc) GOTO(out_trans, rc); rc = dt_trans_start_local(env, d, th); if (rc) GOTO(out_trans, rc); dt_write_lock(env, o, 0); if (dt_object_exists(o)) { if (name) { dt_ref_del(env, o, th); dt_read_lock(env, llog_dir, 0); rc = dt_delete(env, llog_dir, (struct dt_key *) name, th, BYPASS_CAPA); dt_read_unlock(env, llog_dir); if (rc) { CERROR("%s: can't remove llog %s: rc = %d\n", o->do_lu.lo_dev->ld_obd->obd_name, name, rc); GOTO(out_unlock, rc); } } /* * XXX: compatibility bits * on old filesystems llogs are referenced by the name * on the new ones they are referenced by OI and by * the name */ rc = dt_attr_get(env, o, &lgi->lgi_attr, NULL); if (rc) GOTO(out_unlock, rc); LASSERT(lgi->lgi_attr.la_nlink < 2); if (lgi->lgi_attr.la_nlink == 1) dt_ref_del(env, o, th); rc = dt_destroy(env, o, th); if (rc) GOTO(out_unlock, rc); } out_unlock: dt_write_unlock(env, o); out_trans: dt_trans_stop(env, d, th); if (llog_dir != NULL) lu_object_put(env, &llog_dir->do_lu); RETURN(rc); }
static int llog_osd_prev_block(const struct lu_env *env, struct llog_handle *loghandle, int prev_idx, void *buf, int len) { struct llog_thread_info *lgi = llog_info(env); struct dt_object *o; struct dt_device *dt; loff_t cur_offset; int rc; ENTRY; if (len == 0 || len & (LLOG_CHUNK_SIZE - 1)) RETURN(-EINVAL); CDEBUG(D_OTHER, "looking for log index %u\n", prev_idx); LASSERT(loghandle); LASSERT(loghandle->lgh_ctxt); o = loghandle->lgh_obj; LASSERT(o); LASSERT(dt_object_exists(o)); dt = lu2dt_dev(o->do_lu.lo_dev); LASSERT(dt); cur_offset = LLOG_CHUNK_SIZE; llog_skip_over(&cur_offset, 0, prev_idx); rc = dt_attr_get(env, o, &lgi->lgi_attr, BYPASS_CAPA); if (rc) GOTO(out, rc); while (cur_offset < lgi->lgi_attr.la_size) { struct llog_rec_hdr *rec, *last_rec; struct llog_rec_tail *tail; lgi->lgi_buf.lb_len = len; lgi->lgi_buf.lb_buf = buf; /* It is OK to have locking around dt_read() only, see * comment in llog_osd_next_block for details */ dt_read_lock(env, o, 0); rc = dt_read(env, o, &lgi->lgi_buf, &cur_offset); dt_read_unlock(env, o); if (rc < 0) { CERROR("%s: can't read llog block from log "DFID " offset "LPU64": rc = %d\n", o->do_lu.lo_dev->ld_obd->obd_name, PFID(lu_object_fid(&o->do_lu)), cur_offset, rc); GOTO(out, rc); } if (rc == 0) /* end of file, nothing to do */ GOTO(out, rc); if (rc < sizeof(*tail)) { CERROR("%s: invalid llog block at log id "LPU64"/%u " "offset "LPU64"\n", o->do_lu.lo_dev->ld_obd->obd_name, loghandle->lgh_id.lgl_oid, loghandle->lgh_id.lgl_ogen, cur_offset); GOTO(out, rc = -EINVAL); } rec = buf; if (LLOG_REC_HDR_NEEDS_SWABBING(rec)) lustre_swab_llog_rec(rec); tail = (struct llog_rec_tail *)((char *)buf + rc - sizeof(struct llog_rec_tail)); /* get the last record in block */ last_rec = (struct llog_rec_hdr *)((char *)buf + rc - le32_to_cpu(tail->lrt_len)); if (LLOG_REC_HDR_NEEDS_SWABBING(last_rec)) lustre_swab_llog_rec(last_rec); LASSERT(last_rec->lrh_index == tail->lrt_index); /* this shouldn't happen */ if (tail->lrt_index == 0) { CERROR("%s: invalid llog tail at log id "LPU64"/%u " "offset "LPU64"\n", o->do_lu.lo_dev->ld_obd->obd_name, loghandle->lgh_id.lgl_oid, loghandle->lgh_id.lgl_ogen, cur_offset); GOTO(out, rc = -EINVAL); } if (tail->lrt_index < prev_idx) continue; /* sanity check that the start of the new buffer is no farther * than the record that we wanted. This shouldn't happen. */ if (rec->lrh_index > prev_idx) { CERROR("%s: missed desired record? %u > %u\n", o->do_lu.lo_dev->ld_obd->obd_name, rec->lrh_index, prev_idx); GOTO(out, rc = -ENOENT); } GOTO(out, rc = 0); } GOTO(out, rc = -EIO); out: return rc; }
/* sets: * - cur_offset to the furthest point read in the log file * - cur_idx to the log index preceeding cur_offset * returns -EIO/-EINVAL on error */ static int llog_osd_next_block(const struct lu_env *env, struct llog_handle *loghandle, int *cur_idx, int next_idx, __u64 *cur_offset, void *buf, int len) { struct llog_thread_info *lgi = llog_info(env); struct dt_object *o; struct dt_device *dt; int rc; ENTRY; LASSERT(env); LASSERT(lgi); if (len == 0 || len & (LLOG_CHUNK_SIZE - 1)) RETURN(-EINVAL); CDEBUG(D_OTHER, "looking for log index %u (cur idx %u off "LPU64")\n", next_idx, *cur_idx, *cur_offset); LASSERT(loghandle); LASSERT(loghandle->lgh_ctxt); o = loghandle->lgh_obj; LASSERT(o); LASSERT(dt_object_exists(o)); dt = lu2dt_dev(o->do_lu.lo_dev); LASSERT(dt); rc = dt_attr_get(env, o, &lgi->lgi_attr, BYPASS_CAPA); if (rc) GOTO(out, rc); while (*cur_offset < lgi->lgi_attr.la_size) { struct llog_rec_hdr *rec, *last_rec; struct llog_rec_tail *tail; llog_skip_over(cur_offset, *cur_idx, next_idx); /* read up to next LLOG_CHUNK_SIZE block */ lgi->lgi_buf.lb_len = LLOG_CHUNK_SIZE - (*cur_offset & (LLOG_CHUNK_SIZE - 1)); lgi->lgi_buf.lb_buf = buf; /* Note: read lock is not needed around la_size get above at * the time of dt_attr_get(). There are only two cases that * matter. Either la_size == cur_offset, in which case the * entire read is skipped, or la_size > cur_offset and the loop * is entered and this thread is blocked at dt_read_lock() * until the write is completed. When the write completes, then * the dt_read() will be done with the full length, and will * get the full data. */ dt_read_lock(env, o, 0); rc = dt_read(env, o, &lgi->lgi_buf, cur_offset); dt_read_unlock(env, o); if (rc < 0) { CERROR("%s: can't read llog block from log "DFID " offset "LPU64": rc = %d\n", o->do_lu.lo_dev->ld_obd->obd_name, PFID(lu_object_fid(&o->do_lu)), *cur_offset, rc); GOTO(out, rc); } if (rc < len) { /* signal the end of the valid buffer to * llog_process */ memset(buf + rc, 0, len - rc); } if (rc == 0) /* end of file, nothing to do */ GOTO(out, rc); if (rc < sizeof(*tail)) { CERROR("%s: invalid llog block at log id "LPU64"/%u " "offset "LPU64"\n", o->do_lu.lo_dev->ld_obd->obd_name, loghandle->lgh_id.lgl_oid, loghandle->lgh_id.lgl_ogen, *cur_offset); GOTO(out, rc = -EINVAL); } rec = buf; if (LLOG_REC_HDR_NEEDS_SWABBING(rec)) lustre_swab_llog_rec(rec); tail = (struct llog_rec_tail *)((char *)buf + rc - sizeof(struct llog_rec_tail)); /* get the last record in block */ last_rec = (struct llog_rec_hdr *)((char *)buf + rc - le32_to_cpu(tail->lrt_len)); if (LLOG_REC_HDR_NEEDS_SWABBING(last_rec)) lustre_swab_llog_rec(last_rec); LASSERT(last_rec->lrh_index == tail->lrt_index); *cur_idx = tail->lrt_index; /* this shouldn't happen */ if (tail->lrt_index == 0) { CERROR("%s: invalid llog tail at log id "LPU64"/%u " "offset "LPU64"\n", o->do_lu.lo_dev->ld_obd->obd_name, loghandle->lgh_id.lgl_oid, loghandle->lgh_id.lgl_ogen, *cur_offset); GOTO(out, rc = -EINVAL); } if (tail->lrt_index < next_idx) continue; /* sanity check that the start of the new buffer is no farther * than the record that we wanted. This shouldn't happen. */ if (rec->lrh_index > next_idx) { CERROR("%s: missed desired record? %u > %u\n", o->do_lu.lo_dev->ld_obd->obd_name, rec->lrh_index, next_idx); GOTO(out, rc = -ENOENT); } GOTO(out, rc = 0); } GOTO(out, rc = -EIO); out: return rc; }
static int out_attr_get(struct tgt_session_info *tsi) { const struct lu_env *env = tsi->tsi_env; struct tgt_thread_info *tti = tgt_th_info(env); struct obdo *obdo = &tti->tti_u.update.tti_obdo; struct lu_attr *la = &tti->tti_attr; struct dt_object *obj = tti->tti_u.update.tti_dt_object; int rc; ENTRY; if (!lu_object_exists(&obj->do_lu)) RETURN(-ENOENT); dt_read_lock(env, obj, MOR_TGT_CHILD); rc = dt_attr_get(env, obj, la, NULL); if (rc) GOTO(out_unlock, rc); /* * If it is a directory, we will also check whether the * directory is empty. * la_flags = 0 : Empty. * = 1 : Not empty. */ la->la_flags = 0; if (S_ISDIR(la->la_mode)) { struct dt_it *it; const struct dt_it_ops *iops; if (!dt_try_as_dir(env, obj)) GOTO(out_unlock, rc = -ENOTDIR); iops = &obj->do_index_ops->dio_it; it = iops->init(env, obj, LUDA_64BITHASH, BYPASS_CAPA); if (!IS_ERR(it)) { int result; result = iops->get(env, it, (const void *)""); if (result > 0) { int i; for (result = 0, i = 0; result == 0 && i < 3; ++i) result = iops->next(env, it); if (result == 0) la->la_flags = 1; } else if (result == 0) /* * Huh? Index contains no zero key? */ rc = -EIO; iops->put(env, it); iops->fini(env, it); } } obdo->o_valid = 0; obdo_from_la(obdo, la, la->la_valid); obdo_cpu_to_le(obdo, obdo); lustre_set_wire_obdo(NULL, obdo, obdo); out_unlock: dt_read_unlock(env, obj); CDEBUG(D_INFO, "%s: insert attr get reply %p index %d: rc = %d\n", tgt_name(tsi->tsi_tgt), tti->tti_u.update.tti_update_reply, 0, rc); update_insert_reply(tti->tti_u.update.tti_update_reply, obdo, sizeof(*obdo), 0, rc); RETURN(rc); }
static int out_read(struct tgt_session_info *tsi) { const struct lu_env *env = tsi->tsi_env; struct tgt_thread_info *tti = tgt_th_info(env); struct object_update *update = tti->tti_u.update.tti_update; struct dt_object *obj = tti->tti_u.update.tti_dt_object; struct object_update_reply *reply = tti->tti_u.update.tti_update_reply; int index = tti->tti_u.update.tti_update_reply_index; struct lu_rdbuf *rdbuf; struct object_update_result *update_result; struct out_read_reply *orr; void *tmp; size_t size; size_t total_size = 0; __u64 pos; unsigned int i; unsigned int nbufs; int rc = 0; ENTRY; update_result = object_update_result_get(reply, index, NULL); LASSERT(update_result != NULL); update_result->our_datalen = sizeof(*orr); if (!lu_object_exists(&obj->do_lu)) GOTO(out, rc = -ENOENT); tmp = object_update_param_get(update, 0, NULL); if (IS_ERR(tmp)) { CERROR("%s: empty size for read: rc = %ld\n", tgt_name(tsi->tsi_tgt), PTR_ERR(tmp)); GOTO(out, rc = PTR_ERR(tmp)); } size = le64_to_cpu(*(size_t *)(tmp)); tmp = object_update_param_get(update, 1, NULL); if (IS_ERR(tmp)) { CERROR("%s: empty pos for read: rc = %ld\n", tgt_name(tsi->tsi_tgt), PTR_ERR(tmp)); GOTO(out, rc = PTR_ERR(tmp)); } pos = le64_to_cpu(*(__u64 *)(tmp)); /* Put the offset into the begining of the buffer in reply */ orr = (struct out_read_reply *)update_result->our_data; nbufs = (size + OUT_BULK_BUFFER_SIZE - 1) / OUT_BULK_BUFFER_SIZE; OBD_ALLOC(rdbuf, sizeof(struct lu_rdbuf) + nbufs * sizeof(rdbuf->rb_bufs[0])); if (rdbuf == NULL) GOTO(out, rc = -ENOMEM); rdbuf->rb_nbufs = 0; total_size = 0; for (i = 0; i < nbufs; i++) { __u32 read_size; read_size = size > OUT_BULK_BUFFER_SIZE ? OUT_BULK_BUFFER_SIZE : size; OBD_ALLOC(rdbuf->rb_bufs[i].lb_buf, read_size); if (rdbuf->rb_bufs[i].lb_buf == NULL) GOTO(out_free, rc = -ENOMEM); rdbuf->rb_bufs[i].lb_len = read_size; dt_read_lock(env, obj, MOR_TGT_CHILD); rc = dt_read(env, obj, &rdbuf->rb_bufs[i], &pos); dt_read_unlock(env, obj); total_size += rc < 0 ? 0 : rc; if (rc <= 0) break; rdbuf->rb_nbufs++; size -= read_size; } /* send pages to client */ rc = tgt_send_buffer(tsi, rdbuf); if (rc < 0) GOTO(out_free, rc); orr->orr_size = total_size; orr->orr_offset = pos; orr_cpu_to_le(orr, orr); update_result->our_datalen += orr->orr_size; out_free: for (i = 0; i < nbufs; i++) { if (rdbuf->rb_bufs[i].lb_buf != NULL) { OBD_FREE(rdbuf->rb_bufs[i].lb_buf, rdbuf->rb_bufs[i].lb_len); } } OBD_FREE(rdbuf, sizeof(struct lu_rdbuf) + nbufs * sizeof(rdbuf->rb_bufs[0])); out: /* Insert read buffer */ update_result->our_rc = ptlrpc_status_hton(rc); reply->ourp_lens[index] = cfs_size_round(update_result->our_datalen + sizeof(*update_result)); RETURN(rc); }
static int out_attr_get(struct tgt_session_info *tsi) { const struct lu_env *env = tsi->tsi_env; struct tgt_thread_info *tti = tgt_th_info(env); struct obdo *obdo = &tti->tti_u.update.tti_obdo; struct lu_attr *la = &tti->tti_attr; struct dt_object *obj = tti->tti_u.update.tti_dt_object; int idx = tti->tti_u.update.tti_update_reply_index; int rc; ENTRY; if (!lu_object_exists(&obj->do_lu)) { /* Usually, this will be called when the master MDT try * to init a remote object(see osp_object_init), so if * the object does not exist on slave, we need set BANSHEE flag, * so the object can be removed from the cache immediately */ set_bit(LU_OBJECT_HEARD_BANSHEE, &obj->do_lu.lo_header->loh_flags); RETURN(-ENOENT); } dt_read_lock(env, obj, MOR_TGT_CHILD); rc = dt_attr_get(env, obj, la, NULL); if (rc) GOTO(out_unlock, rc); /* * If it is a directory, we will also check whether the * directory is empty. * la_flags = 0 : Empty. * = 1 : Not empty. */ la->la_flags = 0; if (S_ISDIR(la->la_mode)) { struct dt_it *it; const struct dt_it_ops *iops; if (!dt_try_as_dir(env, obj)) GOTO(out_unlock, rc = -ENOTDIR); iops = &obj->do_index_ops->dio_it; it = iops->init(env, obj, LUDA_64BITHASH, BYPASS_CAPA); if (!IS_ERR(it)) { int result; result = iops->get(env, it, (const void *)""); if (result > 0) { int i; for (result = 0, i = 0; result == 0 && i < 3; ++i) result = iops->next(env, it); if (result == 0) la->la_flags = 1; } else if (result == 0) /* * Huh? Index contains no zero key? */ rc = -EIO; iops->put(env, it); iops->fini(env, it); } } obdo->o_valid = 0; obdo_from_la(obdo, la, la->la_valid); obdo_cpu_to_le(obdo, obdo); lustre_set_wire_obdo(NULL, obdo, obdo); out_unlock: dt_read_unlock(env, obj); CDEBUG(D_INFO, "%s: insert attr get reply %p index %d: rc = %d\n", tgt_name(tsi->tsi_tgt), tti->tti_u.update.tti_update_reply, 0, rc); object_update_result_insert(tti->tti_u.update.tti_update_reply, obdo, sizeof(*obdo), idx, rc); RETURN(rc); }