static int llog_changelog_cancel_cb(const struct lu_env *env, struct llog_handle *llh, struct llog_rec_hdr *hdr, void *data) { struct llog_changelog_rec *rec = (struct llog_changelog_rec *)hdr; struct llog_cookie cookie; long long endrec = *(long long *)data; int rc; ENTRY; /* This is always a (sub)log, not the catalog */ LASSERT(llh->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN); if (rec->cr.cr_index > endrec) /* records are in order, so we're done */ RETURN(LLOG_PROC_BREAK); cookie.lgc_lgl = llh->lgh_id; cookie.lgc_index = hdr->lrh_index; /* cancel them one at a time. I suppose we could store up the cookies * and cancel them all at once; probably more efficient, but this is * done as a user call, so who cares... */ rc = llog_cat_cancel_records(env, llh->u.phd.phd_cat_handle, 1, &cookie); RETURN(rc < 0 ? rc : 0); }
/** Two things: * 1. Find the smallest record everyone is willing to purge * 2. Update the last purgeable record for this user */ static int mdd_changelog_user_purge_cb(const struct lu_env *env, struct llog_handle *llh, struct llog_rec_hdr *hdr, void *data) { struct llog_changelog_user_rec *rec; struct mdd_changelog_user_data *mcud = data; int rc; ENTRY; LASSERT(llh->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN); rec = (struct llog_changelog_user_rec *)hdr; mcud->mcud_usercount++; /* If we have a new endrec for this id, use it for the following min check instead of its old value */ if (rec->cur_id == mcud->mcud_id) rec->cur_endrec = max(rec->cur_endrec, mcud->mcud_endrec); /* Track the minimum referenced record */ if (mcud->mcud_minid == 0 || mcud->mcud_minrec > rec->cur_endrec) { mcud->mcud_minid = rec->cur_id; mcud->mcud_minrec = rec->cur_endrec; } if (rec->cur_id != mcud->mcud_id) RETURN(0); /* Update this user's record */ mcud->mcud_found = 1; /* Special case: unregister this user */ if (mcud->mcud_endrec == MCUD_UNREGISTER) { struct llog_cookie cookie; cookie.lgc_lgl = llh->lgh_id; cookie.lgc_index = hdr->lrh_index; rc = llog_cat_cancel_records(env, llh->u.phd.phd_cat_handle, 1, &cookie); if (rc == 0) mcud->mcud_usercount--; RETURN(rc); } /* Update the endrec */ CDEBUG(D_IOCTL, "Rewriting changelog user %d endrec to "LPU64"\n", mcud->mcud_id, rec->cur_endrec); rc = llog_write(env, llh, hdr, hdr->lrh_index); RETURN(rc); }
static int llog_changelog_cancel_cb(struct llog_handle *llh, struct llog_rec_hdr *hdr, void *data) { struct llog_changelog_rec *rec = (struct llog_changelog_rec *)hdr; struct llog_cookie cookie; long long endrec = *(long long *)data; int rc, err; struct obd_device *obd; void *trans_h; struct inode *inode; ENTRY; /* This is always a (sub)log, not the catalog */ LASSERT(llh->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN); if (rec->cr.cr_index > endrec) /* records are in order, so we're done */ RETURN(LLOG_PROC_BREAK); cookie.lgc_lgl = llh->lgh_id; cookie.lgc_index = hdr->lrh_index; obd = llh->lgh_ctxt->loc_exp->exp_obd; inode = llh->lgh_file->f_dentry->d_inode; /* XXX This is a workaround for the deadlock of changelog adding vs. * changelog cancelling. Changelog adding always start transaction * before acquiring the catlog lock (lgh_lock), whereas, changelog * cancelling do start transaction after holding catlog lock. * * We start the transaction earlier here to keep the locking ordering: * 'start transaction -> catlog lock'. LU-81. */ trans_h = fsfilt_start_log(obd, inode, FSFILT_OP_CANCEL_UNLINK, NULL, 1); if (IS_ERR(trans_h)) { CERROR("fsfilt_start_log failed: %ld\n", PTR_ERR(trans_h)); RETURN(PTR_ERR(trans_h)); } /* cancel them one at a time. I suppose we could store up the cookies and cancel them all at once; probably more efficient, but this is done as a user call, so who cares... */ rc = llog_cat_cancel_records(llh->u.phd.phd_cat_handle, 1, &cookie); err = fsfilt_commit(obd, inode, trans_h, 0); if (err) { CERROR("fsfilt_commit failed: %d\n", err); rc = (rc >= 0) ? err : rc; } RETURN(rc < 0 ? rc : 0); }
static int llog_cancel_rec_cb(const struct lu_env *env, struct llog_handle *llh, struct llog_rec_hdr *rec, void *data) { struct llog_cookie cookie; if (!(llh->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN)) { CERROR("log is not plain\n"); return -EINVAL; } cookie.lgc_lgl = llh->lgh_id; cookie.lgc_index = rec->lrh_index; llog_cat_cancel_records(env, llh->u.phd.phd_cat_handle, 1, &cookie); cancel_count++; if (cancel_count == LLOG_TEST_RECNUM) return -LLOG_EEMPTY; return 0; }
static int llog_cancel_rec_cb(struct llog_handle *llh, struct llog_rec_hdr *rec, void *data) { struct llog_cookie cookie; static int i = 0; if (!(llh->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN)) { CERROR("log is not plain\n"); RETURN(-EINVAL); } cookie.lgc_lgl = llh->lgh_id; cookie.lgc_index = rec->lrh_index; llog_cat_cancel_records(llh->u.phd.phd_cat_handle, 1, &cookie); i++; if (i == 40000) RETURN(-4711); RETURN(0); }
/* Test catalogue additions */ static int llog_test_4(const struct lu_env *env, struct obd_device *obd) { struct llog_handle *cath; char name[10]; int rc, rc2, i, buflen; struct llog_mini_rec lmr; struct llog_cookie cookie; struct llog_ctxt *ctxt; int num_recs = 0; char *buf; struct llog_rec_hdr rec; 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; sprintf(name, "%x", llog_test_rand + 1); CWARN("4a: create a catalog log with name: %s\n", name); rc = llog_open_create(env, ctxt, &cath, NULL, name); if (rc) { CERROR("4a: llog_create with name %s failed: %d\n", name, rc); GOTO(ctxt_release, rc); } rc = llog_init_handle(env, cath, LLOG_F_IS_CAT, &uuid); if (rc) { CERROR("4a: can't init llog handle: %d\n", rc); GOTO(out, rc); } num_recs++; cat_logid = cath->lgh_id; CWARN("4b: write 1 record into the catalog\n"); rc = llog_cat_add(env, cath, &lmr.lmr_hdr, &cookie, NULL); if (rc != 1) { CERROR("4b: write 1 catalog record failed at: %d\n", rc); GOTO(out, rc); } num_recs++; rc = verify_handle("4b", cath, 2); if (rc) GOTO(out, rc); rc = verify_handle("4b", cath->u.chd.chd_current_log, num_recs); if (rc) GOTO(out, rc); CWARN("4c: cancel 1 log record\n"); rc = llog_cat_cancel_records(env, cath, 1, &cookie); if (rc) { CERROR("4c: cancel 1 catalog based record failed: %d\n", rc); GOTO(out, rc); } num_recs--; rc = verify_handle("4c", cath->u.chd.chd_current_log, num_recs); if (rc) GOTO(out, rc); CWARN("4d: write %d more log records\n", LLOG_TEST_RECNUM); for (i = 0; i < LLOG_TEST_RECNUM; i++) { rc = llog_cat_add(env, cath, &lmr.lmr_hdr, NULL, NULL); if (rc) { CERROR("4d: write %d records failed at #%d: %d\n", LLOG_TEST_RECNUM, i + 1, rc); GOTO(out, rc); } num_recs++; } /* make sure new plain llog appears */ rc = verify_handle("4d", cath, 3); if (rc) GOTO(out, rc); CWARN("4e: add 5 large records, one record per block\n"); buflen = LLOG_CHUNK_SIZE - sizeof(struct llog_rec_hdr) - sizeof(struct llog_rec_tail); OBD_ALLOC(buf, buflen); if (buf == NULL) GOTO(out, rc = -ENOMEM); for (i = 0; i < 5; i++) { rec.lrh_len = buflen; rec.lrh_type = OBD_CFG_REC; rc = llog_cat_add(env, cath, &rec, NULL, buf); if (rc) { CERROR("4e: write 5 records failed at #%d: %d\n", i + 1, rc); GOTO(out_free, rc); } num_recs++; } out_free: OBD_FREE(buf, buflen); out: CWARN("4f: put newly-created catalog\n"); rc2 = llog_cat_close(env, cath); if (rc2) { CERROR("4: close log %s failed: %d\n", name, rc2); if (rc == 0) rc = rc2; } ctxt_release: llog_ctxt_put(ctxt); return rc; }
int llog_ioctl(struct llog_ctxt *ctxt, int cmd, struct obd_ioctl_data *data) { struct llog_logid logid; int err = 0; struct llog_handle *handle = NULL; ENTRY; if (*data->ioc_inlbuf1 == '#') { err = str2logid(&logid, data->ioc_inlbuf1, data->ioc_inllen1); if (err) GOTO(out, err); err = llog_create(ctxt, &handle, &logid, NULL); if (err) GOTO(out, err); } else if (*data->ioc_inlbuf1 == '$') { char *name = data->ioc_inlbuf1 + 1; err = llog_create(ctxt, &handle, NULL, name); if (err) GOTO(out, err); } else { GOTO(out, err = -EINVAL); } err = llog_init_handle(handle, 0, NULL); if (err) GOTO(out_close, err = -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: #"LPX64"#"LPX64"#%08x\n" "flags: %x (%s)\n" "records count: %d\n" "last index: %d\n", handle->lgh_id.lgl_oid, handle->lgh_id.lgl_oseq, 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("not enough space for log header info\n"); GOTO(out_close, err); } case OBD_IOC_LLOG_CHECK: { LASSERT(data->ioc_inllen1); err = llog_process(handle, llog_check_cb, data, NULL); if (err == -LLOG_EEMPTY) err = 0; GOTO(out_close, err); } case OBD_IOC_LLOG_PRINT: { LASSERT(data->ioc_inllen1); err = llog_process(handle, class_config_dump_handler,data,NULL); if (err == -LLOG_EEMPTY) err = 0; else err = llog_process(handle, llog_print_cb, data, NULL); GOTO(out_close, err); } 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, err = -EINVAL); if (handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT) { cfs_down_write(&handle->lgh_lock); err = llog_cancel_rec(handle, cookie.lgc_index); cfs_up_write(&handle->lgh_lock); GOTO(out_close, err); } err = str2logid(&plain, data->ioc_inlbuf2, data->ioc_inllen2); if (err) GOTO(out_close, err); cookie.lgc_lgl = plain; if (!(handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT)) GOTO(out_close, err = -EINVAL); err = llog_cat_cancel_records(handle, 1, &cookie); GOTO(out_close, err); } case OBD_IOC_LLOG_REMOVE: { struct llog_logid plain; if (handle->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN) { err = llog_destroy(handle); if (!err) llog_free_handle(handle); GOTO(out, err); } if (!(handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT)) GOTO(out_close, err = -EINVAL); if (data->ioc_inlbuf2) { /*remove indicate log from the catalog*/ err = str2logid(&plain, data->ioc_inlbuf2, data->ioc_inllen2); if (err) GOTO(out_close, err); err = llog_remove_log(handle, &plain); } else { /*remove all the log of the catalog*/ llog_process(handle, llog_delete_cb, NULL, NULL); } GOTO(out_close, err); } } out_close: if (handle->lgh_hdr && handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT) llog_cat_put(handle); else llog_close(handle); out: RETURN(err); }
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; }
int llog_origin_handle_cancel(struct ptlrpc_request *req) { struct obd_device *obd = req->rq_export->exp_obd; int num_cookies, rc = 0, err, i, failed = 0; struct obd_device *disk_obd; struct llog_cookie *logcookies; struct llog_ctxt *ctxt = NULL; struct lvfs_run_ctxt saved; struct llog_handle *cathandle; struct inode *inode; void *handle; ENTRY; logcookies = req_capsule_client_get(&req->rq_pill, &RMF_LOGCOOKIES); num_cookies = req_capsule_get_size(&req->rq_pill, &RMF_LOGCOOKIES, RCL_CLIENT) / sizeof(*logcookies); if (logcookies == NULL || num_cookies == 0) { DEBUG_REQ(D_HA, req, "No llog cookies sent"); RETURN(-EFAULT); } ctxt = llog_get_context(obd, logcookies->lgc_subsys); if (ctxt == NULL) RETURN(-ENODEV); disk_obd = ctxt->loc_exp->exp_obd; push_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL); for (i = 0; i < num_cookies; i++, logcookies++) { cathandle = ctxt->loc_handle; LASSERT(cathandle != NULL); inode = cathandle->lgh_file->f_dentry->d_inode; handle = fsfilt_start_log(disk_obd, inode, FSFILT_OP_CANCEL_UNLINK, NULL, 1); if (IS_ERR(handle)) { CERROR("fsfilt_start_log() failed: %ld\n", PTR_ERR(handle)); GOTO(pop_ctxt, rc = PTR_ERR(handle)); } rc = llog_cat_cancel_records(cathandle, 1, logcookies); /* * Do not raise -ENOENT errors for resent rpcs. This rec already * might be killed. */ if (rc == -ENOENT && (lustre_msg_get_flags(req->rq_reqmsg) & MSG_RESENT)) { /* * Do not change this message, reply-single.sh test_59b * expects to find this in log. */ CDEBUG(D_RPCTRACE, "RESENT cancel req %p - ignored\n", req); rc = 0; } else if (rc == 0) { CDEBUG(D_RPCTRACE, "Canceled %d llog-records\n", num_cookies); } err = fsfilt_commit(disk_obd, inode, handle, 0); if (err) { CERROR("Error committing transaction: %d\n", err); if (!rc) rc = err; failed++; GOTO(pop_ctxt, rc); } else if (rc) failed++; } GOTO(pop_ctxt, rc); pop_ctxt: pop_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL); if (rc) CERROR("Cancel %d of %d llog-records failed: %d\n", failed, num_cookies, rc); llog_ctxt_put(ctxt); return rc; }
/* Test catalogue additions */ static int llog_test_4(struct obd_device *obd) { struct llog_handle *cath; char name[10]; int rc, i, buflen; struct llog_mini_rec lmr; struct llog_cookie cookie; struct llog_ctxt *ctxt = llog_get_context(obd, LLOG_TEST_ORIG_CTXT); int num_recs = 0; char *buf; struct llog_rec_hdr rec; ENTRY; lmr.lmr_hdr.lrh_len = lmr.lmr_tail.lrt_len = LLOG_MIN_REC_SIZE; lmr.lmr_hdr.lrh_type = 0xf00f00; sprintf(name, "%x", llog_test_rand+1); CWARN("4a: create a catalog log with name: %s\n", name); rc = llog_create(ctxt, &cath, NULL, name); if (rc) { CERROR("1a: llog_create with name %s failed: %d\n", name, rc); GOTO(out, rc); } llog_init_handle(cath, LLOG_F_IS_CAT, &uuid); num_recs++; cat_logid = cath->lgh_id; CWARN("4b: write 1 record into the catalog\n"); rc = llog_cat_add_rec(cath, &lmr.lmr_hdr, &cookie, NULL); if (rc != 1) { CERROR("4b: write 1 catalog record failed at: %d\n", rc); GOTO(out, rc); } num_recs++; if ((rc = verify_handle("4b", cath, 2))) GOTO(ctxt_release, rc); if ((rc = verify_handle("4b", cath->u.chd.chd_current_log, num_recs))) GOTO(ctxt_release, rc); CWARN("4c: cancel 1 log record\n"); rc = llog_cat_cancel_records(cath, 1, &cookie); if (rc) { CERROR("4c: cancel 1 catalog based record failed: %d\n", rc); GOTO(out, rc); } num_recs--; if ((rc = verify_handle("4c", cath->u.chd.chd_current_log, num_recs))) GOTO(ctxt_release, rc); CWARN("4d: write 40,000 more log records\n"); for (i = 0; i < 40000; i++) { rc = llog_cat_add_rec(cath, &lmr.lmr_hdr, NULL, NULL); if (rc) { CERROR("4d: write 40000 records failed at #%d: %d\n", i + 1, rc); GOTO(out, rc); } num_recs++; } CWARN("4e: add 5 large records, one record per block\n"); buflen = LLOG_CHUNK_SIZE - sizeof(struct llog_rec_hdr) - sizeof(struct llog_rec_tail); OBD_ALLOC(buf, buflen); if (buf == NULL) GOTO(out, rc = -ENOMEM); for (i = 0; i < 5; i++) { rec.lrh_len = buflen; rec.lrh_type = OBD_CFG_REC; rc = llog_cat_add_rec(cath, &rec, NULL, buf); if (rc) { CERROR("4e: write 5 records failed at #%d: %d\n", i + 1, rc); OBD_FREE(buf, buflen); GOTO(out, rc); } num_recs++; } OBD_FREE(buf, buflen); out: CWARN("4f: put newly-created catalog\n"); rc = llog_cat_put(cath); ctxt_release: llog_ctxt_put(ctxt); if (rc) CERROR("1b: close log %s failed: %d\n", name, rc); RETURN(rc); }