X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Fobdclass%2Fllog_test.c;h=902bbaa6e44eaf12990dd1269e22f42be7522768;hp=16606574cccab2d3286d0c434443a49f494ed1bf;hb=26b8238659974959780cd49de92595b4b0bdf89f;hpb=b10b920f383c9cad2c336a059635b4973b75af35 diff --git a/lustre/obdclass/llog_test.c b/lustre/obdclass/llog_test.c index 16606574..902bbaa 100644 --- a/lustre/obdclass/llog_test.c +++ b/lustre/obdclass/llog_test.c @@ -1,38 +1,57 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: +/* + * GPL HEADER START * - * Copyright (C) 2003 Cluster File Systems, Inc. - * Author: Phil Schwan + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * This file is part of Lustre, http://www.lustre.org/ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. * - * Lustre is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 for more details (a copy is included + * in the LICENSE file that accompanied this code). * - * Lustre is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * You should have received a copy of the GNU General Public License - * along with Lustre; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. * - * A kernel module which tests the llog API from the OBD setup function. + * GPL HEADER END + */ +/* + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Use is subject to license terms. + * + * Copyright (c) 2012, 2014, Intel Corporation. + */ +/* + * This file is part of Lustre, http://www.lustre.org/ + * Lustre is a trademark of Sun Microsystems, Inc. + * + * lustre/obdclass/llog_test.c + * + * Author: Phil Schwan + * Author: Mikhail Pershin */ -#ifndef EXPORT_SYMTAB -# define EXPORT_SYMTAB -#endif #define DEBUG_SUBSYSTEM S_CLASS #include #include -#include -#include -#include /* for LUSTRE_MDC_NAME */ +#include +#include +#include + +/* This is slightly more than the number of records that can fit into a + * single llog file, because the llog_log_header takes up some of the + * space in the first block that cannot be used for the bitmap. */ +#define LLOG_TEST_RECNUM (LLOG_CHUNK_SIZE * 8) static int llog_test_rand; static struct obd_uuid uuid = { .uuid = "test_uuid" }; @@ -62,9 +81,9 @@ static int verify_handle(char *test, struct llog_handle *llh, int num_recs) RETURN(-ERANGE); } - if (le32_to_cpu(llh->lgh_hdr->llh_count) != num_recs) { + if (llh->lgh_hdr->llh_count != num_recs) { CERROR("%s: handle->count is %d, expected %d after write\n", - test, le32_to_cpu(llh->lgh_hdr->llh_count), num_recs); + test, llh->lgh_hdr->llh_count, num_recs); RETURN(-ERANGE); } @@ -78,580 +97,1156 @@ static int verify_handle(char *test, struct llog_handle *llh, int num_recs) } /* Test named-log create/open, close */ -static int llog_test_1(struct obd_device *obd, char *name) +static int llog_test_1(const struct lu_env *env, + struct obd_device *obd, char *name) { - struct llog_handle *llh; - struct llog_ctxt *ctxt = llog_get_context(obd, LLOG_TEST_ORIG_CTXT); - int rc; - int rc2; - ENTRY; + struct llog_handle *llh; + struct llog_ctxt *ctxt; + int rc; + int rc2; + + ENTRY; + + CWARN("1a: create a log with name: %s\n", name); + ctxt = llog_get_context(obd, LLOG_TEST_ORIG_CTXT); + LASSERT(ctxt); + + rc = llog_open_create(env, ctxt, &llh, NULL, name); + if (rc) { + CERROR("1a: llog_create with name %s failed: %d\n", name, rc); + GOTO(out, rc); + } + rc = llog_init_handle(env, llh, LLOG_F_IS_PLAIN, &uuid); + if (rc) { + CERROR("1a: can't init llog handle: %d\n", rc); + GOTO(out_close, rc); + } + + rc = verify_handle("1", llh, 1); + + CWARN("1b: close newly-created log\n"); +out_close: + rc2 = llog_close(env, llh); + if (rc2) { + CERROR("1b: close log %s failed: %d\n", name, rc2); + if (rc == 0) + rc = rc2; + } +out: + llog_ctxt_put(ctxt); + RETURN(rc); +} - CERROR("1a: create a log with name: %s\n", name); - LASSERT(ctxt); +/* 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; + + ENTRY; + + 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); +} - rc = llog_create(ctxt, &llh, NULL, name); - if (rc) { - CERROR("1a: llog_create with name %s failed: %d\n", name, rc); - RETURN(rc); - } - llog_init_handle(llh, LLOG_F_IS_PLAIN, &uuid); - - if ((rc = verify_handle("1", llh, 1))) - GOTO(out, rc); - - out: - CERROR("1b: close newly-created log\n"); - rc2 = llog_close(llh); - if (rc2) { - CERROR("1b: close log %s failed: %d\n", name, rc2); - if (rc == 0) - rc = rc2; +/* Test record writing, single and in bulk */ +static int llog_test_3(const struct lu_env *env, struct obd_device *obd, + struct llog_handle *llh) +{ + struct llog_gen_rec lgr; + int rc, i; + int num_recs = 1; /* 1 for the header */ + + ENTRY; + + lgr.lgr_hdr.lrh_len = lgr.lgr_tail.lrt_len = sizeof(lgr); + lgr.lgr_hdr.lrh_type = LLOG_GEN_REC; + + CWARN("3a: write one create_rec\n"); + rc = llog_write(env, llh, &lgr.lgr_hdr, LLOG_NEXT_IDX); + num_recs++; + if (rc < 0) { + CERROR("3a: write one log record failed: %d\n", rc); + RETURN(rc); + } + + rc = verify_handle("3a", llh, num_recs); + if (rc) + RETURN(rc); + + CWARN("3c: write 1000 more log records\n"); + for (i = 0; i < 1000; i++) { + rc = llog_write(env, llh, &lgr.lgr_hdr, LLOG_NEXT_IDX); + if (rc < 0) { + CERROR("3c: write 1000 records failed at #%d: %d\n", + i + 1, rc); + RETURN(rc); + } + num_recs++; + } + + rc = verify_handle("3c", llh, num_recs); + if (rc) + RETURN(rc); + + CWARN("3d: write records with variable size until BITMAP_SIZE, " + "return -ENOSPC\n"); + for (i = 0; i < LLOG_BITMAP_SIZE(llh->lgh_hdr) + 1; i++) { + char buf[64]; + struct llog_rec_hdr *hdr = (void *)&buf; + + memset(buf, 0, sizeof buf); + if ((i % 2) == 0) + hdr->lrh_len = 40; + else + hdr->lrh_len = 64; + hdr->lrh_type = OBD_CFG_REC; + rc = llog_write(env, llh, hdr, LLOG_NEXT_IDX); + + if (rc == -ENOSPC) { + break; + } else if (rc < 0) { + CERROR("3d: write recs failed at #%d: %d\n", + i + 1, rc); + RETURN(rc); + } + num_recs++; + } + if (rc != -ENOSPC) { + CWARN("3d: write record more than BITMAP size!\n"); + RETURN(-EINVAL); + } + CWARN("3d: wrote %d more records before end of llog is reached\n", + num_recs); + + rc = verify_handle("3d", llh, num_recs); + + RETURN(rc); +} + +/* 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; + + 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; + + 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); } - RETURN(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); + 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); + 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; + OBD_ALLOC(buf, buflen); + if (buf == NULL) + GOTO(out, rc = -ENOMEM); + for (i = 0; i < 5; i++) { + rec = (void *)buf; + rec->lrh_len = buflen; + rec->lrh_type = OBD_CFG_REC; + rc = llog_cat_add(env, cath, rec, NULL); + 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); } -/* Test named-log reopen; returns opened log on success */ -static int llog_test_2(struct obd_device *obd, char *name, - struct llog_handle **llh) +static int cat_counter; + +static int cat_print_cb(const struct lu_env *env, struct llog_handle *llh, + struct llog_rec_hdr *rec, void *data) { - struct llog_handle *loghandle; - struct llog_logid logid; - int rc; - struct llog_ctxt *ctxt = llog_get_context(obd, LLOG_TEST_ORIG_CTXT); - ENTRY; + struct llog_logid_rec *lir = (struct llog_logid_rec *)rec; + struct lu_fid fid = {0}; - CERROR("2a: re-open a log with name: %s\n", name); - rc = llog_create(ctxt, llh, NULL, name); - if (rc) { - CERROR("2a: re-open log with name %s failed: %d\n", name, rc); - RETURN(rc); - } - llog_init_handle(*llh, LLOG_F_IS_PLAIN, &uuid); + if (rec->lrh_type != LLOG_LOGID_MAGIC) { + CERROR("invalid record in catalog\n"); + RETURN(-EINVAL); + } - if ((rc = verify_handle("2", *llh, 1))) - RETURN(rc); + logid_to_fid(&lir->lid_id, &fid); - CERROR("2b: create a log without specified NAME & LOGID\n"); - rc = llog_create(ctxt, &loghandle, NULL, NULL); - if (rc) { - CERROR("2b: create log failed\n"); - RETURN(rc); - } - llog_init_handle(loghandle, LLOG_F_IS_PLAIN, &uuid); - logid = loghandle->lgh_id; - llog_close(loghandle); - - CERROR("2b: re-open the log by LOGID\n"); - rc = llog_create(ctxt, &loghandle, &logid, NULL); - if (rc) { - CERROR("2b: re-open log by LOGID failed\n"); - RETURN(rc); - } - llog_init_handle(loghandle, LLOG_F_IS_PLAIN, &uuid); + CWARN("seeing record at index %d - "DFID" in log "DFID"\n", + rec->lrh_index, PFID(&fid), + PFID(lu_object_fid(&llh->lgh_obj->do_lu))); - CERROR("2b: destroy this log\n"); - rc = llog_destroy(loghandle); - if (rc) { - CERROR("2b: destroy log failed\n"); - RETURN(rc); - } - llog_free_handle(loghandle); + cat_counter++; - RETURN(rc); + RETURN(0); } -/* Test record writing, single and in bulk */ -static int llog_test_3(struct obd_device *obd, struct llog_handle *llh) +static int plain_counter; + +static int plain_print_cb(const struct lu_env *env, struct llog_handle *llh, + struct llog_rec_hdr *rec, void *data) { - struct llog_create_rec lcr; - int rc, i; - int num_recs = 1; /* 1 for the header */ - ENTRY; + struct lu_fid fid = {0}; - lcr.lcr_hdr.lrh_len = lcr.lcr_tail.lrt_len = cpu_to_le32(sizeof(lcr)); - lcr.lcr_hdr.lrh_type = cpu_to_le32(OST_SZ_REC); + if (!(llh->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN)) { + CERROR("log is not plain\n"); + RETURN(-EINVAL); + } - CERROR("3a: write one create_rec\n"); - rc = llog_write_rec(llh, &lcr.lcr_hdr, NULL, 0, NULL, -1); - num_recs++; - if (rc) { - CERROR("3a: write one log record failed: %d\n", rc); - RETURN(rc); - } + logid_to_fid(&llh->lgh_id, &fid); - if ((rc = verify_handle("3a", llh, num_recs))) - RETURN(rc); - - CERROR("3b: write 10 cfg log records with 8 bytes bufs\n"); - for (i = 0; i < 10; i++) { - struct llog_rec_hdr hdr; - char buf[8]; - hdr.lrh_len = cpu_to_le32(8); - hdr.lrh_type = cpu_to_le32(OBD_CFG_REC); - memset(buf, 0, sizeof buf); - rc = llog_write_rec(llh, &hdr, NULL, 0, buf, -1); - if (rc) { - CERROR("3b: write 10 records failed at #%d: %d\n", - i + 1, rc); - RETURN(rc); - } - num_recs++; - if ((rc = verify_handle("3c", llh, num_recs))) - RETURN(rc); - } + CDEBUG(D_INFO, "seeing record at index %d in log "DFID"\n", + rec->lrh_index, PFID(&fid)); - if ((rc = verify_handle("3b", llh, num_recs))) - RETURN(rc); + plain_counter++; - CERROR("3c: write 1000 more log records\n"); - for (i = 0; i < 1000; i++) { - rc = llog_write_rec(llh, &lcr.lcr_hdr, NULL, 0, NULL, -1); - if (rc) { - CERROR("3c: write 1000 records failed at #%d: %d\n", - i + 1, rc); - RETURN(rc); - } - num_recs++; - if ((rc = verify_handle("3b", llh, num_recs))) - RETURN(rc); - } - - if ((rc = verify_handle("3c", llh, num_recs))) - RETURN(rc); - - RETURN(rc); + RETURN(0); } -/* Test catalogue additions */ -static int llog_test_4(struct obd_device *obd) +static int cancel_count; + +static int llog_cancel_rec_cb(const struct lu_env *env, + struct llog_handle *llh, + struct llog_rec_hdr *rec, void *data) { - 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; + struct llog_cookie cookie; - ENTRY; + if (!(llh->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN)) { + CERROR("log is not plain\n"); + RETURN(-EINVAL); + } - lmr.lmr_hdr.lrh_len = lmr.lmr_tail.lrt_len = - cpu_to_le32(LLOG_MIN_REC_SIZE); - lmr.lmr_hdr.lrh_type = cpu_to_le32(0xf00f00); + cookie.lgc_lgl = llh->lgh_id; + cookie.lgc_index = rec->lrh_index; - sprintf(name, "%x", llog_test_rand+1); - CERROR("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; - - CERROR("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))) - RETURN(rc); - - if ((rc = verify_handle("4b", cath->u.chd.chd_current_log, num_recs))) - RETURN(rc); - - CERROR("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))) - RETURN(rc); - - CERROR("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++; - } - - CERROR("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 = cpu_to_le32(buflen); - rec.lrh_type = cpu_to_le32(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: - CERROR("4f: put newly-created catalog\n"); - rc = llog_cat_put(cath); - if (rc) - CERROR("1b: close log %s failed: %d\n", name, rc); - RETURN(rc); + 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 cat_print_cb(struct llog_handle *llh, struct llog_rec_hdr *rec, - void *data) +/* Test log and catalogue processing */ +static int llog_test_5(const struct lu_env *env, struct obd_device *obd) { - struct llog_logid_rec *lir = (struct llog_logid_rec *)rec; - - if (le32_to_cpu(rec->lrh_type) != LLOG_LOGID_MAGIC) { - CERROR("invalid record in catalog\n"); - RETURN(-EINVAL); - } - - CERROR("seeing record at index %d - "LPX64":%x in log "LPX64"\n", - le32_to_cpu(rec->lrh_index), lir->lid_id.lgl_oid, - lir->lid_id.lgl_ogen, llh->lgh_id.lgl_oid); - RETURN(0); + struct llog_handle *llh = NULL; + char name[10]; + int rc, rc2; + struct llog_mini_rec lmr; + struct llog_ctxt *ctxt; + + 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("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 llog_cancel_rec_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); + 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); } -static int plain_print_cb(struct llog_handle *llh, struct llog_rec_hdr *rec, - void *data) +/* 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) { - if (!le32_to_cpu(llh->lgh_hdr->llh_flags) & LLOG_F_IS_PLAIN) { - CERROR("log is not plain\n"); - RETURN(-EINVAL); - } + 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\n", 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); - CERROR("seeing record at index %d in log "LPX64"\n", - le32_to_cpu(rec->lrh_index), llh->lgh_id.lgl_oid); - RETURN(0); +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); } -static int llog_cancel_rec_cb(struct llog_handle *llh, struct llog_rec_hdr *rec, - void *data) +static union { + struct llog_rec_hdr lrh; /* common header */ + struct llog_logid_rec llr; /* LLOG_LOGID_MAGIC */ + struct llog_unlink64_rec lur; /* MDS_UNLINK64_REC */ + struct llog_setattr64_rec lsr64; /* MDS_SETATTR64_REC */ + struct llog_size_change_rec lscr; /* OST_SZ_REC */ + struct llog_changelog_rec lcr; /* CHANGELOG_REC */ + struct llog_changelog_user_rec lcur; /* CHANGELOG_USER_REC */ + struct llog_gen_rec lgr; /* LLOG_GEN_REC */ +} llog_records; + +static int test_7_print_cb(const struct lu_env *env, struct llog_handle *llh, + struct llog_rec_hdr *rec, void *data) { - struct llog_cookie cookie; - static int i = 0; + struct lu_fid fid = {0}; - if (!le32_to_cpu(llh->lgh_hdr->llh_flags) & LLOG_F_IS_PLAIN) { - CERROR("log is not plain\n"); - RETURN(-EINVAL); - } + logid_to_fid(&llh->lgh_id, &fid); - cookie.lgc_lgl = llh->lgh_id; - cookie.lgc_index = le32_to_cpu(rec->lrh_index); + CDEBUG(D_OTHER, "record type %#x at index %d in log "DFID"\n", + rec->lrh_type, rec->lrh_index, PFID(&fid)); - llog_cat_cancel_records(llh->u.phd.phd_cat_handle, 1, &cookie); - i++; - if (i == 40000) - RETURN(-4711); - RETURN(0); + plain_counter++; + return 0; } - - -/* Test log and catalogue processing */ -static int llog_test_5(struct obd_device *obd) +static int test_7_cancel_cb(const struct lu_env *env, struct llog_handle *llh, + struct llog_rec_hdr *rec, void *data) { - struct llog_handle *llh = NULL; - char name[10]; - int rc; - struct llog_mini_rec lmr; - struct llog_ctxt *ctxt = llog_get_context(obd, LLOG_TEST_ORIG_CTXT); - - ENTRY; - - lmr.lmr_hdr.lrh_len = lmr.lmr_tail.lrt_len = - cpu_to_le32(LLOG_MIN_REC_SIZE); - lmr.lmr_hdr.lrh_type = cpu_to_le32(0xf00f00); + plain_counter++; + /* test LLOG_DEL_RECORD is working */ + return LLOG_DEL_RECORD; +} - CERROR("5a: re-open catalog by id\n"); - rc = llog_create(ctxt, &llh, &cat_logid, NULL); - if (rc) { - CERROR("5a: llog_create with logid failed: %d\n", rc); - GOTO(out, rc); - } - llog_init_handle(llh, LLOG_F_IS_CAT, &uuid); +static int llog_test_7_sub(const struct lu_env *env, struct llog_ctxt *ctxt) +{ + struct llog_handle *llh; + int rc = 0, i, process_count; + int num_recs = 0; + + ENTRY; + + rc = llog_open_create(env, ctxt, &llh, NULL, NULL); + if (rc) { + CERROR("7_sub: create log failed\n"); + RETURN(rc); + } + + rc = llog_init_handle(env, llh, + LLOG_F_IS_PLAIN | LLOG_F_ZAP_WHEN_EMPTY, + &uuid); + if (rc) { + CERROR("7_sub: can't init llog handle: %d\n", rc); + GOTO(out_close, rc); + } + for (i = 0; i < LLOG_BITMAP_SIZE(llh->lgh_hdr); i++) { + rc = llog_write(env, llh, &llog_records.lrh, LLOG_NEXT_IDX); + if (rc == -ENOSPC) { + break; + } else if (rc < 0) { + CERROR("7_sub: write recs failed at #%d: %d\n", + i + 1, rc); + GOTO(out_close, rc); + } + num_recs++; + } + if (rc != -ENOSPC) { + CWARN("7_sub: write record more than BITMAP size!\n"); + GOTO(out_close, rc = -EINVAL); + } + + rc = verify_handle("7_sub", llh, num_recs + 1); + if (rc) { + CERROR("7_sub: verify handle failed: %d\n", rc); + GOTO(out_close, rc); + } + if (num_recs < LLOG_BITMAP_SIZE(llh->lgh_hdr) - 1) + CWARN("7_sub: records are not aligned, written %d from %u\n", + num_recs, LLOG_BITMAP_SIZE(llh->lgh_hdr) - 1); + + plain_counter = 0; + rc = llog_process(env, llh, test_7_print_cb, "test 7", NULL); + if (rc) { + CERROR("7_sub: llog process failed: %d\n", rc); + GOTO(out_close, rc); + } + process_count = plain_counter; + if (process_count != num_recs) { + CERROR("7_sub: processed %d records from %d total\n", + process_count, num_recs); + GOTO(out_close, rc = -EINVAL); + } + + plain_counter = 0; + rc = llog_reverse_process(env, llh, test_7_cancel_cb, "test 7", NULL); + if (rc && rc != LLOG_DEL_PLAIN) { + CERROR("7_sub: reverse llog process failed: %d\n", rc); + GOTO(out_close, rc); + } + if (process_count != plain_counter) { + CERROR("7_sub: Reverse/direct processing found different" + "number of records: %d/%d\n", + plain_counter, process_count); + GOTO(out_close, rc = -EINVAL); + } + if (llog_exist(llh)) { + CERROR("7_sub: llog exists but should be zapped\n"); + GOTO(out_close, rc = -EEXIST); + } + + rc = verify_handle("7_sub", llh, 1); +out_close: + if (rc) + llog_destroy(env, llh); + llog_close(env, llh); + RETURN(rc); +} - CERROR("5b: print the catalog entries.. we expect 2\n"); - rc = llog_process(llh, (llog_cb_t)cat_print_cb, "test 5"); - if (rc) { - CERROR("5b: process with cat_print_cb failed: %d\n", rc); - GOTO(out, rc); - } +/* Test all llog records writing and processing */ +static int llog_test_7(const struct lu_env *env, struct obd_device *obd) +{ + struct llog_ctxt *ctxt; + int rc; + + ENTRY; + + ctxt = llog_get_context(obd, LLOG_TEST_ORIG_CTXT); + + CWARN("7a: test llog_logid_rec\n"); + llog_records.llr.lid_hdr.lrh_len = sizeof(llog_records.llr); + llog_records.llr.lid_tail.lrt_len = sizeof(llog_records.llr); + llog_records.llr.lid_hdr.lrh_type = LLOG_LOGID_MAGIC; + + rc = llog_test_7_sub(env, ctxt); + if (rc) { + CERROR("7a: llog_logid_rec test failed\n"); + GOTO(out, rc); + } + + CWARN("7b: test llog_unlink64_rec\n"); + llog_records.lur.lur_hdr.lrh_len = sizeof(llog_records.lur); + llog_records.lur.lur_tail.lrt_len = sizeof(llog_records.lur); + llog_records.lur.lur_hdr.lrh_type = MDS_UNLINK64_REC; + + rc = llog_test_7_sub(env, ctxt); + if (rc) { + CERROR("7b: llog_unlink_rec test failed\n"); + GOTO(out, rc); + } + + CWARN("7c: test llog_setattr64_rec\n"); + llog_records.lsr64.lsr_hdr.lrh_len = sizeof(llog_records.lsr64); + llog_records.lsr64.lsr_tail.lrt_len = sizeof(llog_records.lsr64); + llog_records.lsr64.lsr_hdr.lrh_type = MDS_SETATTR64_REC; + + rc = llog_test_7_sub(env, ctxt); + if (rc) { + CERROR("7c: llog_setattr64_rec test failed\n"); + GOTO(out, rc); + } + + CWARN("7d: test llog_size_change_rec\n"); + llog_records.lscr.lsc_hdr.lrh_len = sizeof(llog_records.lscr); + llog_records.lscr.lsc_tail.lrt_len = sizeof(llog_records.lscr); + llog_records.lscr.lsc_hdr.lrh_type = OST_SZ_REC; + + rc = llog_test_7_sub(env, ctxt); + if (rc) { + CERROR("7d: llog_size_change_rec test failed\n"); + GOTO(out, rc); + } + + CWARN("7e: test llog_changelog_rec\n"); + /* Direct access to cr_do_not_use: peculiar case for this test */ + llog_records.lcr.cr_hdr.lrh_len = sizeof(llog_records.lcr); + llog_records.lcr.cr_do_not_use.lrt_len = sizeof(llog_records.lcr); + llog_records.lcr.cr_hdr.lrh_type = CHANGELOG_REC; + + rc = llog_test_7_sub(env, ctxt); + if (rc) { + CERROR("7e: llog_changelog_rec test failed\n"); + GOTO(out, rc); + } + + CWARN("7f: test llog_changelog_user_rec\n"); + llog_records.lcur.cur_hdr.lrh_len = sizeof(llog_records.lcur); + llog_records.lcur.cur_tail.lrt_len = sizeof(llog_records.lcur); + llog_records.lcur.cur_hdr.lrh_type = CHANGELOG_USER_REC; + + rc = llog_test_7_sub(env, ctxt); + if (rc) { + CERROR("7f: llog_changelog_user_rec test failed\n"); + GOTO(out, rc); + } + + CWARN("7g: test llog_gen_rec\n"); + llog_records.lgr.lgr_hdr.lrh_len = sizeof(llog_records.lgr); + llog_records.lgr.lgr_tail.lrt_len = sizeof(llog_records.lgr); + llog_records.lgr.lgr_hdr.lrh_type = LLOG_GEN_REC; + + rc = llog_test_7_sub(env, ctxt); + if (rc) { + CERROR("7g: llog_size_change_rec test failed\n"); + GOTO(out, rc); + } +out: + llog_ctxt_put(ctxt); + RETURN(rc); +} - CERROR("5c: Cancel 40000 records, see one log zapped\n"); - rc = llog_cat_process(llh, llog_cancel_rec_cb, "foobar"); - if (rc != -4711) { - CERROR("5c: process with cat_cancel_cb failed: %d\n", rc); - GOTO(out, rc); - } +static int llog_truncate(const struct lu_env *env, struct dt_object *o) +{ + struct lu_attr la; + struct thandle *th; + struct dt_device *d; + int rc; + ENTRY; - CERROR("5d: add 1 record to the log with many canceled empty pages\n"); - rc = llog_cat_add_rec(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); - } + LASSERT(o); + d = lu2dt_dev(o->do_lu.lo_dev); + LASSERT(d); - CERROR("5b: print the catalog entries.. we expect 1\n"); - rc = llog_process(llh, (llog_cb_t)cat_print_cb, "test 5"); - if (rc) { - CERROR("5b: process with cat_print_cb failed: %d\n", rc); - GOTO(out, rc); - } + rc = dt_attr_get(env, o, &la); + if (rc) + RETURN(rc); - CERROR("5e: print plain log entries.. expect 6\n"); - rc = llog_cat_process(llh, plain_print_cb, "foobar"); - if (rc) { - CERROR("5e: process with plain_print_cb failed: %d\n", rc); - GOTO(out, rc); - } + CDEBUG(D_OTHER, "original size "LPU64"\n", la.la_size); + rc = sizeof(struct llog_log_hdr) + sizeof(struct llog_mini_rec); + if (la.la_size < rc) { + CERROR("too small llog: "LPU64"\n", la.la_size); + RETURN(0); + } - out: - CERROR("5: close re-opened catalog\n"); - if (llh) - rc = llog_cat_put(llh); - if (rc) - CERROR("1b: close log %s failed: %d\n", name, rc); - RETURN(rc); -} + /* drop 2 records */ + la.la_size = la.la_size - (sizeof(struct llog_mini_rec) * 2); + la.la_valid = LA_SIZE; -/* Test client api; open log by name and process */ -static int llog_test_6(struct obd_device *obd, char *name) -{ - struct obd_device *mdc_obd; - struct llog_ctxt *ctxt = llog_get_context(obd, LLOG_TEST_ORIG_CTXT); - struct obd_uuid *mds_uuid = &ctxt->loc_exp->exp_obd->obd_uuid; - struct lustre_handle exph = {0, }; - struct obd_export *exp; - struct obd_uuid uuid = {"LLOG_TEST6_UUID"}; - struct llog_handle *llh = NULL; - struct llog_ctxt *nctxt; - int rc; - - CERROR("6a: re-open log %s using client API\n", name); - mdc_obd = class_find_client_obd(mds_uuid, LUSTRE_MDC_NAME, NULL); - if (mdc_obd == NULL) { - CERROR("6: no MDC devices connected to %s found.\n", - mds_uuid->uuid); - RETURN(-ENOENT); - } + th = dt_trans_create(env, d); + if (IS_ERR(th)) + RETURN(PTR_ERR(th)); - rc = obd_connect(&exph, mdc_obd, &uuid); - if (rc) { - CERROR("6: failed to connect to MDC: %s\n", mdc_obd->obd_name); - RETURN(rc); - } - exp = class_conn2export(&exph); + rc = dt_declare_attr_set(env, o, &la, th); + if (rc) + GOTO(stop, rc); - nctxt = llog_get_context(mdc_obd, LLOG_CONFIG_REPL_CTXT); - rc = llog_create(nctxt, &llh, NULL, name); - if (rc) { - CERROR("6: llog_create failed %d\n", rc); - RETURN(rc); - } + rc = dt_declare_punch(env, o, la.la_size, OBD_OBJECT_EOF, th); - rc = llog_init_handle(llh, LLOG_F_IS_PLAIN, NULL); - if (rc) { - CERROR("6: llog_init_handle failed %d\n", rc); - GOTO(parse_out, rc); - } + rc = dt_trans_start_local(env, d, th); + if (rc) + GOTO(stop, rc); - rc = llog_process(llh, (llog_cb_t)plain_print_cb, NULL); - if (rc) - CERROR("6: llog_process failed %d\n", rc); + rc = dt_punch(env, o, la.la_size, OBD_OBJECT_EOF, th); + if (rc) + GOTO(stop, rc); -parse_out: - rc = llog_close(llh); - if (rc) { - CERROR("6: llog_close failed: rc = %d\n", rc); - } + rc = dt_attr_set(env, o, &la, th); + if (rc) + GOTO(stop, rc); - rc = obd_disconnect(exp, 0); +stop: + dt_trans_stop(env, d, th); - RETURN(rc); + RETURN(rc); } -/* ------------------------------------------------------------------------- - * Tests above, boring obd functions below - * ------------------------------------------------------------------------- */ -static int llog_run_tests(struct obd_device *obd) +static int test_8_cb(const struct lu_env *env, struct llog_handle *llh, + struct llog_rec_hdr *rec, void *data) { - struct llog_handle *llh; - struct obd_run_ctxt saved; - struct llog_ctxt *ctxt = llog_get_context(obd, LLOG_TEST_ORIG_CTXT); - int rc, err, cleanup_phase = 0; - char name[10]; - ENTRY; - - sprintf(name, "%x", llog_test_rand); - push_ctxt(&saved, &ctxt->loc_exp->exp_obd->obd_ctxt, NULL); - - rc = llog_test_1(obd, name); - if (rc) - GOTO(cleanup, rc); - - rc = llog_test_2(obd, name, &llh); - if (rc) - GOTO(cleanup, rc); - cleanup_phase = 1; /* close llh */ - - rc = llog_test_3(obd, llh); - if (rc) - GOTO(cleanup, rc); - - rc = llog_test_4(obd); - if (rc) - GOTO(cleanup, rc); - - rc = llog_test_5(obd); - if (rc) - GOTO(cleanup, rc); - - rc = llog_test_6(obd, name); - if (rc) - GOTO(cleanup, rc); - - cleanup: - switch (cleanup_phase) { - case 1: - err = llog_close(llh); - if (err) - CERROR("cleanup: llog_close failed: %d\n", err); - if (!rc) - rc = err; - case 0: - pop_ctxt(&saved, &ctxt->loc_exp->exp_obd->obd_ctxt, NULL); - } - - return rc; + plain_counter++; + return 0; } - -static int llog_test_llog_init(struct obd_device *obd, struct obd_device *tgt, - int count, struct llog_logid *logid) +static int llog_test_8(const struct lu_env *env, struct obd_device *obd) { - int rc; - ENTRY; - - rc = llog_setup(obd, LLOG_TEST_ORIG_CTXT, tgt, 0, NULL, &llog_lvfs_ops); - RETURN(rc); + 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); } -static int llog_test_llog_finish(struct obd_device *obd, int count) +/* ------------------------------------------------------------------------- + * Tests above, boring obd functions below + * ------------------------------------------------------------------------- */ +static int llog_run_tests(const struct lu_env *env, struct obd_device *obd) { - int rc; - ENTRY; - - rc = llog_cleanup(llog_get_context(obd, LLOG_TEST_ORIG_CTXT)); - RETURN(rc); + struct llog_handle *llh = NULL; + struct llog_ctxt *ctxt; + int rc, err; + char name[10]; + + ENTRY; + ctxt = llog_get_context(obd, LLOG_TEST_ORIG_CTXT); + LASSERT(ctxt); + + sprintf(name, "%x", llog_test_rand); + + rc = llog_test_1(env, obd, name); + if (rc) + GOTO(cleanup_ctxt, rc); + + rc = llog_test_2(env, obd, name, &llh); + if (rc) + GOTO(cleanup_ctxt, rc); + + rc = llog_test_3(env, obd, llh); + if (rc) + GOTO(cleanup, rc); + + rc = llog_test_4(env, obd); + if (rc) + GOTO(cleanup, rc); + + rc = llog_test_5(env, obd); + if (rc) + GOTO(cleanup, rc); + + rc = llog_test_6(env, obd, name); + if (rc) + GOTO(cleanup, rc); + + rc = llog_test_7(env, obd); + if (rc) + GOTO(cleanup, rc); + + rc = llog_test_8(env, obd); + if (rc) + GOTO(cleanup, rc); + +cleanup: + err = llog_destroy(env, llh); + if (err) + CERROR("cleanup: llog_destroy failed: %d\n", err); + llog_close(env, llh); + if (rc == 0) + rc = err; +cleanup_ctxt: + llog_ctxt_put(ctxt); + return rc; } -static int llog_test_cleanup(struct obd_device *obd, int flags) +static int llog_test_cleanup(struct obd_device *obd) { - int rc = obd_llog_finish(obd, 0); - if (rc) - CERROR("failed to llog_test_llog_finish: %d\n", rc); - - return rc; + struct obd_device *tgt; + struct lu_env env; + int rc; + + ENTRY; + + rc = lu_env_init(&env, LCT_LOCAL | LCT_MG_THREAD); + if (rc) + RETURN(rc); + + tgt = obd->obd_lvfs_ctxt.dt->dd_lu_dev.ld_obd; + rc = llog_cleanup(&env, llog_get_context(tgt, LLOG_TEST_ORIG_CTXT)); + if (rc) + CERROR("failed to llog_test_llog_finish: %d\n", rc); + lu_env_fini(&env); + RETURN(rc); } -static int llog_test_setup(struct obd_device *obd, obd_count len, void *buf) +static int llog_test_setup(struct obd_device *obd, struct lustre_cfg *lcfg) { - struct lustre_cfg *lcfg = buf; - struct obd_device *tgt; - int rc; + struct obd_device *tgt; + struct llog_ctxt *ctxt; + struct dt_object *o; + struct lu_env env; + struct lu_context test_session; + int rc; + ENTRY; - if (lcfg->lcfg_inllen1 < 1) { + if (lcfg->lcfg_bufcount < 2) { + CERROR("requires a TARGET OBD name\n"); + RETURN(-EINVAL); + } + + if (lcfg->lcfg_buflens[1] < 1) { CERROR("requires a TARGET OBD name\n"); RETURN(-EINVAL); } - tgt = class_name2obd(lcfg->lcfg_inlbuf1); + /* disk obd */ + tgt = class_name2obd(lustre_cfg_string(lcfg, 1)); if (!tgt || !tgt->obd_attached || !tgt->obd_set_up) { CERROR("target device not attached or not set up (%s)\n", - lcfg->lcfg_inlbuf1); + lustre_cfg_string(lcfg, 1)); RETURN(-EINVAL); } - rc = obd_llog_init(obd, tgt, 0, NULL); - if (rc) - RETURN(rc); - - llog_test_rand = ll_insecure_random_int(); - - rc = llog_run_tests(obd); - if (rc) - llog_test_cleanup(obd, 0); - RETURN(rc); -} - -static struct lprocfs_vars lprocfs_ost_obd_vars[] = { {0} }; -static struct lprocfs_vars lprocfs_ost_module_vars[] = { {0} }; -LPROCFS_INIT_VARS(ost, lprocfs_ost_module_vars, lprocfs_ost_obd_vars) - -static int llog_test_attach(struct obd_device *dev, obd_count len, void *data) -{ - struct lprocfs_static_vars lvars; - - lprocfs_init_vars(ost, &lvars); - return lprocfs_obd_attach(dev, lvars.obd_vars); -} - -static int llog_test_detach(struct obd_device *dev) -{ - return lprocfs_obd_detach(dev); + rc = lu_env_init(&env, LCT_LOCAL | LCT_MG_THREAD); + if (rc) + RETURN(rc); + + rc = lu_context_init(&test_session, LCT_SERVER_SESSION); + if (rc) + GOTO(cleanup_env, rc); + test_session.lc_thread = (struct ptlrpc_thread *)current; + lu_context_enter(&test_session); + env.le_ses = &test_session; + + CWARN("Setup llog-test device over %s device\n", + lustre_cfg_string(lcfg, 1)); + + OBD_SET_CTXT_MAGIC(&obd->obd_lvfs_ctxt); + obd->obd_lvfs_ctxt.dt = lu2dt_dev(tgt->obd_lu_dev); + + rc = llog_setup(&env, tgt, &tgt->obd_olg, LLOG_TEST_ORIG_CTXT, tgt, + &llog_osd_ops); + if (rc) + GOTO(cleanup_session, rc); + + /* use MGS llog dir for tests */ + ctxt = llog_get_context(tgt, LLOG_CONFIG_ORIG_CTXT); + LASSERT(ctxt); + o = ctxt->loc_dir; + llog_ctxt_put(ctxt); + + ctxt = llog_get_context(tgt, LLOG_TEST_ORIG_CTXT); + LASSERT(ctxt); + ctxt->loc_dir = o; + llog_ctxt_put(ctxt); + + llog_test_rand = cfs_rand(); + + rc = llog_run_tests(&env, tgt); + if (rc) + llog_test_cleanup(obd); +cleanup_session: + lu_context_exit(&test_session); + lu_context_fini(&test_session); +cleanup_env: + lu_env_fini(&env); + RETURN(rc); } static struct obd_ops llog_obd_ops = { - o_owner: THIS_MODULE, - o_attach: llog_test_attach, - o_detach: llog_test_detach, - o_setup: llog_test_setup, - o_cleanup: llog_test_cleanup, - o_llog_init: llog_test_llog_init, - o_llog_finish: llog_test_llog_finish, - + .o_owner = THIS_MODULE, + .o_setup = llog_test_setup, + .o_cleanup = llog_test_cleanup, }; -static struct lprocfs_vars lprocfs_obd_vars[] = { {0} }; -static struct lprocfs_vars lprocfs_module_vars[] = { {0} }; -LPROCFS_INIT_VARS(llog_test, lprocfs_module_vars, lprocfs_obd_vars) - static int __init llog_test_init(void) { - struct lprocfs_static_vars lvars; - - lprocfs_init_vars(llog_test, &lvars); - return class_register_type(&llog_obd_ops,lvars.module_vars,"llog_test"); + return class_register_type(&llog_obd_ops, NULL, true, NULL, + "llog_test", NULL); } static void __exit llog_test_exit(void) { - class_unregister_type("llog_test"); + class_unregister_type("llog_test"); } -MODULE_AUTHOR("Cluster File Systems, Inc. "); +MODULE_AUTHOR("Sun Microsystems, Inc. "); MODULE_DESCRIPTION("llog test module"); MODULE_LICENSE("GPL");