/** * Helper function to open llog or create it if doesn't exist. * It hides all transaction handling from caller. */ int llog_open_create(const struct lu_env *env, struct llog_ctxt *ctxt, struct llog_handle **res, struct llog_logid *logid, char *name) { struct dt_device *d; struct thandle *th; int rc; rc = llog_open(env, ctxt, res, logid, name, LLOG_OPEN_NEW); if (rc) return rc; if (llog_exist(*res)) return 0; LASSERT((*res)->lgh_obj != NULL); d = lu2dt_dev((*res)->lgh_obj->do_lu.lo_dev); th = dt_trans_create(env, d); if (IS_ERR(th)) GOTO(out, rc = PTR_ERR(th)); rc = llog_declare_create(env, *res, th); if (rc == 0) { rc = dt_trans_start_local(env, d, th); if (rc == 0) rc = llog_create(env, *res, th); } dt_trans_stop(env, d, th); out: if (rc) llog_close(env, *res); return rc; }
/** * Helper function to delete existent llog. */ int llog_erase(const struct lu_env *env, struct llog_ctxt *ctxt, struct llog_logid *logid, char *name) { struct llog_handle *handle; int rc = 0, rc2; ENTRY; /* nothing to erase */ if (name == NULL && logid == NULL) RETURN(0); rc = llog_open(env, ctxt, &handle, logid, name, LLOG_OPEN_EXISTS); if (rc < 0) RETURN(rc); rc = llog_init_handle(env, handle, LLOG_F_IS_PLAIN, NULL); if (rc == 0) rc = llog_destroy(env, handle); rc2 = llog_close(env, handle); if (rc == 0) rc = rc2; RETURN(rc); }
/** * Helper function to get the llog size in records. It is used by MGS * mostly to check that config llog exists and contains data. * * \param[in] env execution environment * \param[in] ctxt llog context * \param[in] name llog name * * \retval true if there are records in llog besides a header * \retval false on error or llog without records */ int llog_is_empty(const struct lu_env *env, struct llog_ctxt *ctxt, char *name) { struct llog_handle *llh; int rc = 0; rc = llog_open(env, ctxt, &llh, NULL, name, LLOG_OPEN_EXISTS); if (rc < 0) { if (likely(rc == -ENOENT)) rc = 0; GOTO(out, rc); } rc = llog_init_handle(env, llh, LLOG_F_IS_PLAIN, NULL); if (rc) GOTO(out_close, rc); rc = llog_get_size(llh); out_close: llog_close(env, llh); out: /* The header is record 1, the llog is still considered as empty * if there is only header */ return (rc <= 1); }
int llog_origin_handle_next_block(struct ptlrpc_request *req) { struct llog_handle *loghandle; struct llogd_body *body; struct llogd_body *repbody; struct llog_ctxt *ctxt; __u32 flags; void *ptr; int rc; ENTRY; body = req_capsule_client_get(&req->rq_pill, &RMF_LLOGD_BODY); if (body == NULL) RETURN(err_serious(-EFAULT)); req_capsule_set_size(&req->rq_pill, &RMF_EADATA, RCL_SERVER, LLOG_MIN_CHUNK_SIZE); rc = req_capsule_server_pack(&req->rq_pill); if (rc) RETURN(err_serious(-ENOMEM)); if (body->lgd_ctxt_idx >= LLOG_MAX_CTXTS) { CDEBUG(D_WARNING, "%s: bad ctxt ID: idx=%d\n", req->rq_export->exp_obd->obd_name, body->lgd_ctxt_idx); RETURN(-EPROTO); } ctxt = llog_get_context(req->rq_export->exp_obd, body->lgd_ctxt_idx); if (ctxt == NULL) RETURN(-ENODEV); rc = llog_open(req->rq_svc_thread->t_env, ctxt, &loghandle, &body->lgd_logid, NULL, LLOG_OPEN_EXISTS); if (rc) GOTO(out_ctxt, rc); flags = body->lgd_llh_flags; rc = llog_init_handle(req->rq_svc_thread->t_env, loghandle, flags, NULL); if (rc) GOTO(out_close, rc); repbody = req_capsule_server_get(&req->rq_pill, &RMF_LLOGD_BODY); *repbody = *body; ptr = req_capsule_server_get(&req->rq_pill, &RMF_EADATA); rc = llog_next_block(req->rq_svc_thread->t_env, loghandle, &repbody->lgd_saved_index, repbody->lgd_index, &repbody->lgd_cur_offset, ptr, LLOG_MIN_CHUNK_SIZE); if (rc) GOTO(out_close, rc); EXIT; out_close: llog_origin_close(req->rq_svc_thread->t_env, loghandle); out_ctxt: llog_ctxt_put(ctxt); return rc; }
/* Only open is supported, no new llog can be created remotely */ int llog_origin_handle_open(struct ptlrpc_request *req) { struct obd_export *exp = req->rq_export; struct obd_device *obd = exp->exp_obd; struct llog_handle *loghandle; struct llogd_body *body; struct llog_logid *logid = NULL; struct llog_ctxt *ctxt; char *name = NULL; int rc; ENTRY; body = req_capsule_client_get(&req->rq_pill, &RMF_LLOGD_BODY); if (body == NULL) RETURN(err_serious(-EFAULT)); rc = req_capsule_server_pack(&req->rq_pill); if (rc) RETURN(err_serious(-ENOMEM)); if (ostid_id(&body->lgd_logid.lgl_oi) > 0) logid = &body->lgd_logid; if (req_capsule_field_present(&req->rq_pill, &RMF_NAME, RCL_CLIENT)) { name = req_capsule_client_get(&req->rq_pill, &RMF_NAME); if (name == NULL) RETURN(-EFAULT); CDEBUG(D_INFO, "%s: opening log %s\n", obd->obd_name, name); } if (body->lgd_ctxt_idx >= LLOG_MAX_CTXTS) { CDEBUG(D_WARNING, "%s: bad ctxt ID: idx=%d name=%s\n", obd->obd_name, body->lgd_ctxt_idx, name); RETURN(-EPROTO); } ctxt = llog_get_context(obd, body->lgd_ctxt_idx); if (ctxt == NULL) { CDEBUG(D_WARNING, "%s: no ctxt. group=%p idx=%d name=%s\n", obd->obd_name, &obd->obd_olg, body->lgd_ctxt_idx, name); RETURN(-ENODEV); } rc = llog_open(req->rq_svc_thread->t_env, ctxt, &loghandle, logid, name, LLOG_OPEN_EXISTS); if (rc) GOTO(out_ctxt, rc); body = req_capsule_server_get(&req->rq_pill, &RMF_LLOGD_BODY); body->lgd_logid = loghandle->lgh_id; llog_origin_close(req->rq_svc_thread->t_env, loghandle); EXIT; out_ctxt: llog_ctxt_put(ctxt); return rc; }
int llog_origin_handle_read_header(struct ptlrpc_request *req) { struct llog_handle *loghandle; struct llogd_body *body; struct llog_log_hdr *hdr; struct llog_ctxt *ctxt; __u32 flags; int rc; ENTRY; body = req_capsule_client_get(&req->rq_pill, &RMF_LLOGD_BODY); if (body == NULL) RETURN(err_serious(-EFAULT)); rc = req_capsule_server_pack(&req->rq_pill); if (rc) RETURN(err_serious(-ENOMEM)); if (body->lgd_ctxt_idx >= LLOG_MAX_CTXTS) { CDEBUG(D_WARNING, "%s: bad ctxt ID: idx=%d\n", req->rq_export->exp_obd->obd_name, body->lgd_ctxt_idx); RETURN(-EPROTO); } ctxt = llog_get_context(req->rq_export->exp_obd, body->lgd_ctxt_idx); if (ctxt == NULL) RETURN(-ENODEV); rc = llog_open(req->rq_svc_thread->t_env, ctxt, &loghandle, &body->lgd_logid, NULL, LLOG_OPEN_EXISTS); if (rc) GOTO(out_ctxt, rc); /* * llog_init_handle() reads the llog header */ flags = body->lgd_llh_flags; rc = llog_init_handle(req->rq_svc_thread->t_env, loghandle, flags, NULL); if (rc) GOTO(out_close, rc); flags = loghandle->lgh_hdr->llh_flags; hdr = req_capsule_server_get(&req->rq_pill, &RMF_LLOG_LOG_HDR); *hdr = *loghandle->lgh_hdr; EXIT; out_close: llog_origin_close(req->rq_svc_thread->t_env, loghandle); out_ctxt: llog_ctxt_put(ctxt); return rc; }
/** * Helper function to open llog or create it if doesn't exist. * It hides all transaction handling from caller. */ int llog_open_create(const struct lu_env *env, struct llog_ctxt *ctxt, struct llog_handle **res, struct llog_logid *logid, char *name) { struct dt_device *d; struct thandle *th; int rc; ENTRY; rc = llog_open(env, ctxt, res, logid, name, LLOG_OPEN_NEW); if (rc) RETURN(rc); if (llog_exist(*res)) RETURN(0); LASSERT((*res)->lgh_obj != NULL); d = lu2dt_dev((*res)->lgh_obj->do_lu.lo_dev); th = dt_trans_create(env, d); if (IS_ERR(th)) GOTO(out, rc = PTR_ERR(th)); /* Create update llog object synchronously, which * happens during inialization process see * lod_sub_prep_llog(), to make sure the update * llog object is created before corss-MDT writing * updates into the llog object */ if (ctxt->loc_flags & LLOG_CTXT_FLAG_NORMAL_FID) th->th_sync = 1; th->th_wait_submit = 1; rc = llog_declare_create(env, *res, th); if (rc == 0) { rc = dt_trans_start_local(env, d, th); if (rc == 0) rc = llog_create(env, *res, th); } dt_trans_stop(env, d, th); out: if (rc) llog_close(env, *res); RETURN(rc); }
int llog_is_empty(const struct lu_env *env, struct llog_ctxt *ctxt, char *name) { struct llog_handle *llh; int rc = 0; rc = llog_open(env, ctxt, &llh, NULL, name, LLOG_OPEN_EXISTS); if (rc < 0) { if (likely(rc == -ENOENT)) rc = 0; goto out; } rc = llog_init_handle(env, llh, LLOG_F_IS_PLAIN, NULL); if (rc) goto out_close; rc = llog_get_size(llh); out_close: llog_close(env, llh); out: /* header is record 1 */ return rc <= 1; }
/* Test client api; open log by name and process */ static int llog_test_6(const struct lu_env *env, struct obd_device *obd, char *name) { struct obd_device *mgc_obd; struct llog_ctxt *ctxt; struct obd_uuid *mgs_uuid; struct obd_export *exp; struct obd_uuid uuid = { "LLOG_TEST6_UUID" }; struct llog_handle *llh = NULL; struct llog_ctxt *nctxt; int rc, rc2; ctxt = llog_get_context(obd, LLOG_TEST_ORIG_CTXT); LASSERT(ctxt); mgs_uuid = &ctxt->loc_exp->exp_obd->obd_uuid; CWARN("6a: re-open log %s using client API\n", name); mgc_obd = class_find_client_obd(mgs_uuid, LUSTRE_MGC_NAME, NULL); if (mgc_obd == NULL) { CERROR("6a: no MGC devices connected to %s found.\n", mgs_uuid->uuid); GOTO(ctxt_release, rc = -ENOENT); } rc = obd_connect(NULL, &exp, mgc_obd, &uuid, NULL /* obd_connect_data */, NULL); if (rc != -EALREADY) { CERROR("6a: connect on connected MGC (%s) failed to return" " -EALREADY", mgc_obd->obd_name); if (rc == 0) obd_disconnect(exp); GOTO(ctxt_release, rc = -EINVAL); } nctxt = llog_get_context(mgc_obd, LLOG_CONFIG_REPL_CTXT); rc = llog_open(env, nctxt, &llh, NULL, name, LLOG_OPEN_EXISTS); if (rc) { CERROR("6a: llog_open failed %d\n", rc); GOTO(nctxt_put, rc); } rc = llog_init_handle(env, llh, LLOG_F_IS_PLAIN, NULL); if (rc) { CERROR("6a: llog_init_handle failed %d\n", rc); GOTO(parse_out, rc); } plain_counter = 1; /* llog header is first record */ CWARN("6b: process log %s using client API\n", name); rc = llog_process(env, llh, plain_print_cb, NULL, NULL); if (rc) CERROR("6b: llog_process failed %d\n", rc); CWARN("6b: processed %d records\n", plain_counter); rc = verify_handle("6b", llh, plain_counter); if (rc) GOTO(parse_out, rc); plain_counter = 1; /* llog header is first record */ CWARN("6c: process log %s reversely using client API\n", name); rc = llog_reverse_process(env, llh, plain_print_cb, NULL, NULL); if (rc) CERROR("6c: llog_reverse_process failed %d\n", rc); CWARN("6c: processed %d records\n", plain_counter); rc = verify_handle("6c", llh, plain_counter); if (rc) GOTO(parse_out, rc); parse_out: rc2 = llog_close(env, llh); if (rc2) { CERROR("6: llog_close failed: rc = %d\n", rc2); if (rc == 0) rc = rc2; } nctxt_put: llog_ctxt_put(nctxt); ctxt_release: llog_ctxt_put(ctxt); return rc; }
/* Test log and catalogue processing */ static int llog_test_5(const struct lu_env *env, struct obd_device *obd) { struct llog_handle *llh = NULL; char name[10]; int rc, rc2; struct llog_mini_rec lmr; struct llog_ctxt *ctxt; ctxt = llog_get_context(obd, LLOG_TEST_ORIG_CTXT); LASSERT(ctxt); lmr.lmr_hdr.lrh_len = lmr.lmr_tail.lrt_len = LLOG_MIN_REC_SIZE; lmr.lmr_hdr.lrh_type = 0xf00f00; CWARN("5a: re-open catalog by id\n"); rc = llog_open(env, ctxt, &llh, &cat_logid, NULL, LLOG_OPEN_EXISTS); if (rc) { CERROR("5a: llog_create with logid failed: %d\n", rc); GOTO(out_put, rc); } rc = llog_init_handle(env, llh, LLOG_F_IS_CAT, &uuid); if (rc) { CERROR("5a: can't init llog handle: %d\n", rc); GOTO(out, rc); } CWARN("5b: print the catalog entries.. we expect 2\n"); cat_counter = 0; rc = llog_process(env, llh, cat_print_cb, "test 5", NULL); if (rc) { CERROR("5b: process with cat_print_cb failed: %d\n", rc); GOTO(out, rc); } if (cat_counter != 2) { CERROR("5b: %d entries in catalog\n", cat_counter); GOTO(out, rc = -EINVAL); } CWARN("5c: Cancel %d records, see one log zapped\n", LLOG_TEST_RECNUM); cancel_count = 0; rc = llog_cat_process(env, llh, llog_cancel_rec_cb, "foobar", 0, 0); if (rc != -LLOG_EEMPTY) { CERROR("5c: process with cat_cancel_cb failed: %d\n", rc); GOTO(out, rc); } CWARN("5c: print the catalog entries.. we expect 1\n"); cat_counter = 0; rc = llog_process(env, llh, cat_print_cb, "test 5", NULL); if (rc) { CERROR("5c: process with cat_print_cb failed: %d\n", rc); GOTO(out, rc); } if (cat_counter != 1) { CERROR("5c: %d entries in catalog\n", cat_counter); GOTO(out, rc = -EINVAL); } CWARN("5d: add 1 record to the log with many canceled empty pages\n"); rc = llog_cat_add(env, llh, &lmr.lmr_hdr, NULL, NULL); if (rc) { CERROR("5d: add record to the log with many canceled empty " "pages failed\n"); GOTO(out, rc); } CWARN("5e: print plain log entries.. expect 6\n"); plain_counter = 0; rc = llog_cat_process(env, llh, plain_print_cb, "foobar", 0, 0); if (rc) { CERROR("5e: process with plain_print_cb failed: %d\n", rc); GOTO(out, rc); } if (plain_counter != 6) { CERROR("5e: found %d records\n", plain_counter); GOTO(out, rc = -EINVAL); } CWARN("5f: print plain log entries reversely.. expect 6\n"); plain_counter = 0; rc = llog_cat_reverse_process(env, llh, plain_print_cb, "foobar"); if (rc) { CERROR("5f: reversely process with plain_print_cb failed:" "%d\n", rc); GOTO(out, rc); } if (plain_counter != 6) { CERROR("5f: found %d records\n", plain_counter); GOTO(out, rc = -EINVAL); } out: CWARN("5g: close re-opened catalog\n"); rc2 = llog_cat_close(env, llh); if (rc2) { CERROR("5g: close log %s failed: %d\n", name, rc2); if (rc == 0) rc = rc2; } out_put: llog_ctxt_put(ctxt); return rc; }
/* Test named-log reopen; returns opened log on success */ static int llog_test_2(const struct lu_env *env, struct obd_device *obd, char *name, struct llog_handle **llh) { struct llog_ctxt *ctxt; struct llog_handle *loghandle; struct llog_logid logid; int rc; CWARN("2a: re-open a log with name: %s\n", name); ctxt = llog_get_context(obd, LLOG_TEST_ORIG_CTXT); LASSERT(ctxt); rc = llog_open(env, ctxt, llh, NULL, name, LLOG_OPEN_EXISTS); if (rc) { CERROR("2a: re-open log with name %s failed: %d\n", name, rc); GOTO(out_put, rc); } rc = llog_init_handle(env, *llh, LLOG_F_IS_PLAIN, &uuid); if (rc) { CERROR("2a: can't init llog handle: %d\n", rc); GOTO(out_close_llh, rc); } rc = verify_handle("2", *llh, 1); if (rc) GOTO(out_close_llh, rc); /* XXX: there is known issue with tests 2b, MGS is not able to create * anonymous llog, exit now to allow following tests run. * It is fixed in upcoming llog over OSD code */ GOTO(out_put, rc); CWARN("2b: create a log without specified NAME & LOGID\n"); rc = llog_open_create(env, ctxt, &loghandle, NULL, NULL); if (rc) { CERROR("2b: create log failed\n"); GOTO(out_close_llh, rc); } rc = llog_init_handle(env, loghandle, LLOG_F_IS_PLAIN, &uuid); if (rc) { CERROR("2b: can't init llog handle: %d\n", rc); GOTO(out_close, rc); } logid = loghandle->lgh_id; llog_close(env, loghandle); CWARN("2c: re-open the log by LOGID\n"); rc = llog_open(env, ctxt, &loghandle, &logid, NULL, LLOG_OPEN_EXISTS); if (rc) { CERROR("2c: re-open log by LOGID failed\n"); GOTO(out_close_llh, rc); } rc = llog_init_handle(env, loghandle, LLOG_F_IS_PLAIN, &uuid); if (rc) { CERROR("2c: can't init llog handle: %d\n", rc); GOTO(out_close, rc); } CWARN("2b: destroy this log\n"); rc = llog_destroy(env, loghandle); if (rc) CERROR("2d: destroy log failed\n"); out_close: llog_close(env, loghandle); out_close_llh: if (rc) llog_close(env, *llh); out_put: llog_ctxt_put(ctxt); return rc; }
/* backup plain llog */ int llog_backup(const struct lu_env *env, struct obd_device *obd, struct llog_ctxt *ctxt, struct llog_ctxt *bctxt, char *name, char *backup) { struct llog_handle *llh, *bllh; int rc; /* open original log */ rc = llog_open(env, ctxt, &llh, NULL, name, LLOG_OPEN_EXISTS); if (rc < 0) { /* the -ENOENT case is also reported to the caller * but silently so it should handle that if needed. */ if (rc != -ENOENT) CERROR("%s: failed to open log %s: rc = %d\n", obd->obd_name, name, rc); return rc; } rc = llog_init_handle(env, llh, LLOG_F_IS_PLAIN, NULL); if (rc) GOTO(out_close, rc); /* Make sure there's no old backup log */ rc = llog_erase(env, bctxt, NULL, backup); if (rc < 0 && rc != -ENOENT) GOTO(out_close, rc); /* open backup log */ rc = llog_open_create(env, bctxt, &bllh, NULL, backup); if (rc) { CERROR("%s: failed to open backup logfile %s: rc = %d\n", obd->obd_name, backup, rc); GOTO(out_close, rc); } /* check that backup llog is not the same object as original one */ if (llh->lgh_obj == bllh->lgh_obj) { CERROR("%s: backup llog %s to itself (%s), objects %p/%p\n", obd->obd_name, name, backup, llh->lgh_obj, bllh->lgh_obj); GOTO(out_backup, rc = -EEXIST); } rc = llog_init_handle(env, bllh, LLOG_F_IS_PLAIN, NULL); if (rc) GOTO(out_backup, rc); /* Copy log record by record */ rc = llog_process_or_fork(env, llh, llog_copy_handler, (void *)bllh, NULL, false); if (rc) CERROR("%s: failed to backup log %s: rc = %d\n", obd->obd_name, name, rc); out_backup: llog_close(env, bllh); out_close: llog_close(env, llh); return rc; }
int llog_ioctl(const struct lu_env *env, struct llog_ctxt *ctxt, int cmd, struct obd_ioctl_data *data) { struct llog_logid logid; int rc = 0; struct llog_handle *handle = NULL; if (*data->ioc_inlbuf1 == '#') { rc = str2logid(&logid, data->ioc_inlbuf1, data->ioc_inllen1); if (rc) return rc; rc = llog_open(env, ctxt, &handle, &logid, NULL, LLOG_OPEN_EXISTS); if (rc) return rc; } else if (*data->ioc_inlbuf1 == '$') { char *name = data->ioc_inlbuf1 + 1; rc = llog_open(env, ctxt, &handle, NULL, name, LLOG_OPEN_EXISTS); if (rc) return rc; } else { return -EINVAL; } rc = llog_init_handle(env, handle, 0, NULL); if (rc) GOTO(out_close, rc = -ENOENT); switch (cmd) { case OBD_IOC_LLOG_INFO: { int l; int remains = data->ioc_inllen2 + cfs_size_round(data->ioc_inllen1); char *out = data->ioc_bulk; l = snprintf(out, remains, "logid: #"DOSTID"#%08x\n" "flags: %x (%s)\n" "records count: %d\n" "last index: %d\n", POSTID(&handle->lgh_id.lgl_oi), handle->lgh_id.lgl_ogen, handle->lgh_hdr->llh_flags, handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT ? "cat" : "plain", handle->lgh_hdr->llh_count, handle->lgh_last_idx); out += l; remains -= l; if (remains <= 0) { CERROR("%s: not enough space for log header info\n", ctxt->loc_obd->obd_name); rc = -ENOSPC; } break; } case OBD_IOC_LLOG_CHECK: LASSERT(data->ioc_inllen1 > 0); rc = llog_process(env, handle, llog_check_cb, data, NULL); if (rc == -LLOG_EEMPTY) rc = 0; else if (rc) GOTO(out_close, rc); break; case OBD_IOC_LLOG_PRINT: LASSERT(data->ioc_inllen1 > 0); rc = llog_process(env, handle, llog_print_cb, data, NULL); if (rc == -LLOG_EEMPTY) rc = 0; else if (rc) GOTO(out_close, rc); break; case OBD_IOC_LLOG_CANCEL: { struct llog_cookie cookie; struct llog_logid plain; char *endp; cookie.lgc_index = simple_strtoul(data->ioc_inlbuf3, &endp, 0); if (*endp != '\0') GOTO(out_close, rc = -EINVAL); if (handle->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN) { rc = llog_cancel_rec(NULL, handle, cookie.lgc_index); GOTO(out_close, rc); } else if (!(handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT)) { GOTO(out_close, rc = -EINVAL); } if (data->ioc_inlbuf2 == NULL) /* catalog but no logid */ GOTO(out_close, rc = -ENOTTY); rc = str2logid(&plain, data->ioc_inlbuf2, data->ioc_inllen2); if (rc) GOTO(out_close, rc); cookie.lgc_lgl = plain; rc = llog_cat_cancel_records(env, handle, 1, &cookie); if (rc) GOTO(out_close, rc); break; } case OBD_IOC_LLOG_REMOVE: { struct llog_logid plain; if (handle->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN) { rc = llog_destroy(env, handle); GOTO(out_close, rc); } else if (!(handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT)) { GOTO(out_close, rc = -EINVAL); } if (data->ioc_inlbuf2 > 0) { /* remove indicate log from the catalog */ rc = str2logid(&plain, data->ioc_inlbuf2, data->ioc_inllen2); if (rc) GOTO(out_close, rc); rc = llog_remove_log(env, handle, &plain); } else { /* remove all the log of the catalog */ rc = llog_process(env, handle, llog_delete_cb, NULL, NULL); if (rc) GOTO(out_close, rc); } break; } default: CERROR("%s: Unknown ioctl cmd %#x\n", ctxt->loc_obd->obd_name, cmd); GOTO(out_close, rc = -ENOTTY); } out_close: if (handle->lgh_hdr && handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT) llog_cat_close(env, handle); else llog_close(env, handle); return rc; }
static int llog_test_8(const struct lu_env *env, struct obd_device *obd) { struct llog_handle *llh = NULL; char name[10]; int rc, rc2, i; int orig_counter; struct llog_mini_rec lmr; struct llog_ctxt *ctxt; struct dt_object *obj = NULL; ENTRY; ctxt = llog_get_context(obd, LLOG_TEST_ORIG_CTXT); LASSERT(ctxt); lmr.lmr_hdr.lrh_len = lmr.lmr_tail.lrt_len = LLOG_MIN_REC_SIZE; lmr.lmr_hdr.lrh_type = 0xf00f00; CWARN("8a: fill the first plain llog\n"); rc = llog_open(env, ctxt, &llh, &cat_logid, NULL, LLOG_OPEN_EXISTS); if (rc) { CERROR("8a: llog_create with logid failed: %d\n", rc); GOTO(out_put, rc); } rc = llog_init_handle(env, llh, LLOG_F_IS_CAT, &uuid); if (rc) { CERROR("8a: can't init llog handle: %d\n", rc); GOTO(out, rc); } plain_counter = 0; rc = llog_cat_process(env, llh, test_8_cb, "foobar", 0, 0); if (rc != 0) { CERROR("5a: process with test_8_cb failed: %d\n", rc); GOTO(out, rc); } orig_counter = plain_counter; for (i = 0; i < 100; i++) { rc = llog_cat_add(env, llh, &lmr.lmr_hdr, NULL); if (rc) { CERROR("5a: add record failed\n"); GOTO(out, rc); } } /* grab the current plain llog, we'll corrupt it later */ obj = llh->u.chd.chd_current_log->lgh_obj; LASSERT(obj); lu_object_get(&obj->do_lu); CWARN("8a: pin llog "DFID"\n", PFID(lu_object_fid(&obj->do_lu))); rc2 = llog_cat_close(env, llh); if (rc2) { CERROR("8a: close log %s failed: %d\n", name, rc2); if (rc == 0) rc = rc2; GOTO(out_put, rc); } CWARN("8b: fill the second plain llog\n"); rc = llog_open(env, ctxt, &llh, &cat_logid, NULL, LLOG_OPEN_EXISTS); if (rc) { CERROR("8b: llog_create with logid failed: %d\n", rc); GOTO(out_put, rc); } rc = llog_init_handle(env, llh, LLOG_F_IS_CAT, &uuid); if (rc) { CERROR("8b: can't init llog handle: %d\n", rc); GOTO(out, rc); } for (i = 0; i < 100; i++) { rc = llog_cat_add(env, llh, &lmr.lmr_hdr, NULL); if (rc) { CERROR("8b: add record failed\n"); GOTO(out, rc); } } CWARN("8b: second llog "DFID"\n", PFID(lu_object_fid(&llh->u.chd.chd_current_log->lgh_obj->do_lu))); rc2 = llog_cat_close(env, llh); if (rc2) { CERROR("8b: close log %s failed: %d\n", name, rc2); if (rc == 0) rc = rc2; GOTO(out_put, rc); } CWARN("8c: drop two records from the first plain llog\n"); llog_truncate(env, obj); CWARN("8d: count survived records\n"); rc = llog_open(env, ctxt, &llh, &cat_logid, NULL, LLOG_OPEN_EXISTS); if (rc) { CERROR("8d: llog_create with logid failed: %d\n", rc); GOTO(out_put, rc); } rc = llog_init_handle(env, llh, LLOG_F_IS_CAT, &uuid); if (rc) { CERROR("8d: can't init llog handle: %d\n", rc); GOTO(out, rc); } plain_counter = 0; rc = llog_cat_process(env, llh, test_8_cb, "foobar", 0, 0); if (rc != 0) { CERROR("8d: process with test_8_cb failed: %d\n", rc); GOTO(out, rc); } if (orig_counter + 200 - 2 != plain_counter) { CERROR("found %d records (expected %d)\n", plain_counter, orig_counter + 200 - 2); rc = -EIO; } out: CWARN("8d: close re-opened catalog\n"); rc2 = llog_cat_close(env, llh); if (rc2) { CERROR("8d: close log %s failed: %d\n", name, rc2); if (rc == 0) rc = rc2; } out_put: llog_ctxt_put(ctxt); if (obj != NULL) lu_object_put(env, &obj->do_lu); RETURN(rc); }