* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, 2013, Intel Corporation.
+ * Copyright (c) 2012, 2014, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
#define DEBUG_SUBSYSTEM S_LOG
-#ifndef __KERNEL__
-#include <liblustre.h>
-#endif
#include <obd_class.h>
struct llog_handle *loghandle,
struct thandle *th)
{
+ struct llog_thread_info *lgi = llog_info(env);
+ struct llog_logid_rec *rec = &lgi->lgi_logid;
+ int rc;
- struct llog_log_hdr *llh;
- struct llog_logid_rec rec = { { 0 }, };
- int rc, index, bitmap_size;
- ENTRY;
-
- llh = cathandle->lgh_hdr;
- bitmap_size = LLOG_BITMAP_SIZE(llh);
-
- index = (cathandle->lgh_last_idx + 1) % bitmap_size;
-
- /* maximum number of available slots in catlog is bitmap_size - 2 */
- if (llh->llh_cat_idx == index) {
- CERROR("no free catalog slots for log...\n");
- RETURN(-ENOSPC);
- }
+ ENTRY;
if (OBD_FAIL_CHECK(OBD_FAIL_MDS_LLOG_CREATE_FAILED))
RETURN(-ENOSPC);
+ if (loghandle->lgh_hdr != NULL) {
+ /* If llog object is remote and creation is failed, lgh_hdr
+ * might be left over here, free it first */
+ LASSERT(!llog_exist(loghandle));
+ OBD_FREE_PTR(loghandle->lgh_hdr);
+ loghandle->lgh_hdr = NULL;
+ }
+
rc = llog_create(env, loghandle, th);
/* if llog is already created, no need to initialize it */
if (rc == -EEXIST) {
}
rc = llog_init_handle(env, loghandle,
- LLOG_F_IS_PLAIN | LLOG_F_ZAP_WHEN_EMPTY,
- &cathandle->lgh_hdr->llh_tgtuuid);
- if (rc)
- GOTO(out_destroy, rc);
-
- if (index == 0)
- index = 1;
-
- spin_lock(&loghandle->lgh_hdr_lock);
- llh->llh_count++;
- if (ext2_set_bit(index, llh->llh_bitmap)) {
- CERROR("argh, index %u already set in log bitmap?\n",
- index);
- spin_unlock(&loghandle->lgh_hdr_lock);
- LBUG(); /* should never happen */
- }
- spin_unlock(&loghandle->lgh_hdr_lock);
+ LLOG_F_IS_PLAIN | LLOG_F_ZAP_WHEN_EMPTY,
+ &cathandle->lgh_hdr->llh_tgtuuid);
+ if (rc)
+ GOTO(out_destroy, rc);
- cathandle->lgh_last_idx = index;
- llh->llh_tail.lrt_index = index;
+ /* build the record for this log in the catalog */
+ rec->lid_hdr.lrh_len = sizeof(*rec);
+ rec->lid_hdr.lrh_type = LLOG_LOGID_MAGIC;
+ rec->lid_id = loghandle->lgh_id;
- CDEBUG(D_RPCTRACE,"new recovery log "DOSTID":%x for index %u of catalog"
- DOSTID"\n", POSTID(&loghandle->lgh_id.lgl_oi),
- loghandle->lgh_id.lgl_ogen, index,
- POSTID(&cathandle->lgh_id.lgl_oi));
- /* build the record for this log in the catalog */
- rec.lid_hdr.lrh_len = sizeof(rec);
- rec.lid_hdr.lrh_index = index;
- rec.lid_hdr.lrh_type = LLOG_LOGID_MAGIC;
- rec.lid_id = loghandle->lgh_id;
- rec.lid_tail.lrt_len = sizeof(rec);
- rec.lid_tail.lrt_index = index;
-
- /* update the catalog: header and record */
- rc = llog_write_rec(env, cathandle, &rec.lid_hdr,
- &loghandle->u.phd.phd_cookie, 1, NULL, index, th);
+ /* append the new record into catalog. The new index will be
+ * assigned to the record and updated in rec header */
+ rc = llog_write_rec(env, cathandle, &rec->lid_hdr,
+ &loghandle->u.phd.phd_cookie, LLOG_NEXT_IDX, th);
if (rc < 0)
GOTO(out_destroy, rc);
- loghandle->lgh_hdr->llh_cat_idx = index;
+ CDEBUG(D_OTHER, "new recovery log "DOSTID":%x for index %u of catalog"
+ DOSTID"\n", POSTID(&loghandle->lgh_id.lgl_oi),
+ loghandle->lgh_id.lgl_ogen, rec->lid_hdr.lrh_index,
+ POSTID(&cathandle->lgh_id.lgl_oi));
+
+ loghandle->lgh_hdr->llh_cat_idx = rec->lid_hdr.lrh_index;
RETURN(0);
out_destroy:
llog_destroy(env, loghandle);
struct llog_handle **res, struct llog_logid *logid)
{
struct llog_handle *loghandle;
+ enum llog_flag fmt;
int rc = 0;
ENTRY;
if (cathandle == NULL)
RETURN(-EBADF);
+ fmt = cathandle->lgh_hdr->llh_flags & LLOG_F_EXT_MASK;
down_write(&cathandle->lgh_lock);
- cfs_list_for_each_entry(loghandle, &cathandle->u.chd.chd_head,
- u.phd.phd_entry) {
+ list_for_each_entry(loghandle, &cathandle->u.chd.chd_head,
+ u.phd.phd_entry) {
struct llog_logid *cgl = &loghandle->lgh_id;
if (ostid_id(&cgl->lgl_oi) == ostid_id(&logid->lgl_oi) &&
RETURN(rc);
}
- rc = llog_init_handle(env, loghandle, LLOG_F_IS_PLAIN, NULL);
+ rc = llog_init_handle(env, loghandle, LLOG_F_IS_PLAIN | fmt, NULL);
if (rc < 0) {
llog_close(env, loghandle);
loghandle = NULL;
}
down_write(&cathandle->lgh_lock);
- cfs_list_add(&loghandle->u.phd.phd_entry, &cathandle->u.chd.chd_head);
+ list_add_tail(&loghandle->u.phd.phd_entry, &cathandle->u.chd.chd_head);
up_write(&cathandle->lgh_lock);
loghandle->u.phd.phd_cat_handle = cathandle;
ENTRY;
- cfs_list_for_each_entry_safe(loghandle, n, &cathandle->u.chd.chd_head,
- u.phd.phd_entry) {
+ list_for_each_entry_safe(loghandle, n, &cathandle->u.chd.chd_head,
+ u.phd.phd_entry) {
struct llog_log_hdr *llh = loghandle->lgh_hdr;
int index;
/* unlink open-not-created llogs */
- cfs_list_del_init(&loghandle->u.phd.phd_entry);
+ list_del_init(&loghandle->u.phd.phd_entry);
llh = loghandle->lgh_hdr;
if (loghandle->lgh_obj != NULL && llh != NULL &&
(llh->llh_flags & LLOG_F_ZAP_WHEN_EMPTY) &&
down_write_nested(&loghandle->lgh_lock, LLOGH_LOG);
llh = loghandle->lgh_hdr;
if (llh == NULL ||
- loghandle->lgh_last_idx < LLOG_BITMAP_SIZE(llh) - 1) {
+ loghandle->lgh_last_idx < LLOG_HDR_BITMAP_SIZE(llh) - 1) {
up_read(&cathandle->lgh_lock);
RETURN(loghandle);
} else {
down_write_nested(&loghandle->lgh_lock, LLOGH_LOG);
llh = loghandle->lgh_hdr;
LASSERT(llh);
- if (loghandle->lgh_last_idx < LLOG_BITMAP_SIZE(llh) - 1) {
+ if (loghandle->lgh_last_idx < LLOG_HDR_BITMAP_SIZE(llh) - 1) {
up_write(&cathandle->lgh_lock);
- RETURN(loghandle);
- } else {
+ RETURN(loghandle);
+ } else {
up_write(&loghandle->lgh_lock);
- }
+ }
}
CDEBUG(D_INODE, "use next log\n");
*/
int llog_cat_add_rec(const struct lu_env *env, struct llog_handle *cathandle,
struct llog_rec_hdr *rec, struct llog_cookie *reccookie,
- void *buf, struct thandle *th)
+ struct thandle *th)
{
struct llog_handle *loghandle;
int rc;
ENTRY;
- LASSERT(rec->lrh_len <= LLOG_CHUNK_SIZE);
+ LASSERT(rec->lrh_len <= cathandle->lgh_ctxt->loc_chunk_size);
loghandle = llog_cat_current_log(cathandle, th);
LASSERT(!IS_ERR(loghandle));
}
}
/* now let's try to add the record */
- rc = llog_write_rec(env, loghandle, rec, reccookie, 1, buf, -1, th);
+ rc = llog_write_rec(env, loghandle, rec, reccookie, LLOG_NEXT_IDX, th);
if (rc < 0)
CDEBUG_LIMIT(rc == -ENOSPC ? D_HA : D_ERROR,
"llog_write_rec %d: lh=%p\n", rc, loghandle);
}
}
/* now let's try to add the record */
- rc = llog_write_rec(env, loghandle, rec, reccookie, 1, buf,
- -1, th);
+ rc = llog_write_rec(env, loghandle, rec, reccookie,
+ LLOG_NEXT_IDX, th);
if (rc < 0)
CERROR("llog_write_rec %d: lh=%p\n", rc, loghandle);
up_write(&loghandle->lgh_lock);
struct llog_handle *cathandle,
struct llog_rec_hdr *rec, struct thandle *th)
{
+ struct llog_thread_info *lgi = llog_info(env);
+ struct llog_logid_rec *lirec = &lgi->lgi_logid;
struct llog_handle *loghandle, *next;
int rc = 0;
NULL, NULL, LLOG_OPEN_NEW);
if (rc == 0) {
cathandle->u.chd.chd_current_log = loghandle;
- cfs_list_add_tail(&loghandle->u.phd.phd_entry,
- &cathandle->u.chd.chd_head);
+ list_add_tail(&loghandle->u.phd.phd_entry,
+ &cathandle->u.chd.chd_head);
}
}
up_write(&cathandle->lgh_lock);
NULL, NULL, LLOG_OPEN_NEW);
if (rc == 0) {
cathandle->u.chd.chd_next_log = loghandle;
- cfs_list_add_tail(&loghandle->u.phd.phd_entry,
- &cathandle->u.chd.chd_head);
+ list_add_tail(&loghandle->u.phd.phd_entry,
+ &cathandle->u.chd.chd_head);
}
}
up_write(&cathandle->lgh_lock);
if (rc)
GOTO(out, rc);
+ lirec->lid_hdr.lrh_len = sizeof(*lirec);
+
if (!llog_exist(cathandle->u.chd.chd_current_log)) {
rc = llog_declare_create(env, cathandle->u.chd.chd_current_log,
th);
if (rc)
GOTO(out, rc);
- llog_declare_write_rec(env, cathandle, NULL, -1, th);
+ llog_declare_write_rec(env, cathandle, &lirec->lid_hdr, -1, th);
}
/* declare records in the llogs */
rc = llog_declare_write_rec(env, cathandle->u.chd.chd_current_log,
if (next) {
if (!llog_exist(next)) {
rc = llog_declare_create(env, next, th);
- llog_declare_write_rec(env, cathandle, NULL, -1, th);
+ llog_declare_write_rec(env, cathandle, &lirec->lid_hdr,
+ -1, th);
}
- llog_declare_write_rec(env, next, rec, -1, th);
+ /* XXX: we hope for declarations made for existing llog
+ * this might be not correct with some backends
+ * where declarations are expected against specific
+ * object like ZFS with full debugging enabled */
+ /*llog_declare_write_rec(env, next, rec, -1, th);*/
}
out:
RETURN(rc);
EXPORT_SYMBOL(llog_cat_declare_add_rec);
int llog_cat_add(const struct lu_env *env, struct llog_handle *cathandle,
- struct llog_rec_hdr *rec, struct llog_cookie *reccookie,
- void *buf)
+ struct llog_rec_hdr *rec, struct llog_cookie *reccookie)
{
struct llog_ctxt *ctxt;
struct dt_device *dt;
rc = dt_trans_start_local(env, dt, th);
if (rc)
GOTO(out_trans, rc);
- rc = llog_cat_add_rec(env, cathandle, rec, reccookie, buf, th);
+ rc = llog_cat_add_rec(env, cathandle, rec, reccookie, th);
out_trans:
dt_trans_stop(env, dt, th);
RETURN(rc);
}
EXPORT_SYMBOL(llog_cat_cancel_records);
-int llog_cat_process_cb(const struct lu_env *env, struct llog_handle *cat_llh,
- struct llog_rec_hdr *rec, void *data)
+static int llog_cat_process_cb(const struct lu_env *env,
+ struct llog_handle *cat_llh,
+ struct llog_rec_hdr *rec, void *data)
{
struct llog_process_data *d = data;
struct llog_logid_rec *lir = (struct llog_logid_rec *)rec;
struct llog_handle *llh;
+ struct llog_log_hdr *hdr;
int rc;
ENTRY;
CERROR("%s: cannot find handle for llog "DOSTID": %d\n",
cat_llh->lgh_ctxt->loc_obd->obd_name,
POSTID(&lir->lid_id.lgl_oi), rc);
+ if (rc == -ENOENT || rc == -ESTALE) {
+ /* After a server crash, a stub of index
+ * record in catlog could be kept, because
+ * plain log destroy + catlog index record
+ * deletion are not atomic. So we end up with
+ * an index but no actual record. Destroy the
+ * index and move on. */
+ rc = llog_cat_cleanup(env, cat_llh, NULL,
+ rec->lrh_index);
+ }
+
RETURN(rc);
}
+ /* clean old empty llogs, do not consider current llog in use */
+ /* ignore remote (lgh_obj=NULL) llogs */
+ hdr = llh->lgh_hdr;
+ if ((hdr->llh_flags & LLOG_F_ZAP_WHEN_EMPTY) &&
+ hdr->llh_count == 1 && cat_llh->lgh_obj != NULL &&
+ llh != cat_llh->u.chd.chd_current_log) {
+ rc = llog_destroy(env, llh);
+ if (rc)
+ CERROR("%s: fail to destroy empty log: rc = %d\n",
+ llh->lgh_ctxt->loc_obd->obd_name, rc);
+ GOTO(out, rc = LLOG_DEL_PLAIN);
+ }
+
if (rec->lrh_index < d->lpd_startcat) {
/* Skip processing of the logs until startcat */
rc = 0;
NULL, false);
}
+out:
/* The empty plain log was destroyed while processing */
if (rc == LLOG_DEL_PLAIN)
rc = llog_cat_cleanup(env, cat_llh, llh,
RETURN(rc);
}
-EXPORT_SYMBOL(llog_cat_process_or_fork);
int llog_cat_process(const struct lu_env *env, struct llog_handle *cat_llh,
llog_cb_t cb, void *data, int startcat, int startidx)
struct llog_process_data *d = data;
struct llog_logid_rec *lir = (struct llog_logid_rec *)rec;
struct llog_handle *llh;
+ struct llog_log_hdr *hdr;
int rc;
if (le32_to_cpu(rec->lrh_type) != LLOG_LOGID_MAGIC) {
CERROR("%s: cannot find handle for llog "DOSTID": %d\n",
cat_llh->lgh_ctxt->loc_obd->obd_name,
POSTID(&lir->lid_id.lgl_oi), rc);
+ if (rc == -ENOENT || rc == -ESTALE) {
+ /* After a server crash, a stub of index
+ * record in catlog could be kept, because
+ * plain log destroy + catlog index record
+ * deletion are not atomic. So we end up with
+ * an index but no actual record. Destroy the
+ * index and move on. */
+ rc = llog_cat_cleanup(env, cat_llh, NULL,
+ rec->lrh_index);
+ }
+
RETURN(rc);
}
+ /* clean old empty llogs, do not consider current llog in use */
+ hdr = llh->lgh_hdr;
+ if ((hdr->llh_flags & LLOG_F_ZAP_WHEN_EMPTY) &&
+ hdr->llh_count == 1 &&
+ llh != cat_llh->u.chd.chd_current_log) {
+ rc = llog_destroy(env, llh);
+ if (rc)
+ CERROR("%s: fail to destroy empty log: rc = %d\n",
+ llh->lgh_ctxt->loc_obd->obd_name, rc);
+ GOTO(out, rc = LLOG_DEL_PLAIN);
+ }
+
rc = llog_reverse_process(env, llh, d->lpd_cb, d->lpd_data, NULL);
+out:
/* The empty plain was destroyed while processing */
if (rc == LLOG_DEL_PLAIN)
rc = llog_cat_cleanup(env, cat_llh, llh,
}
EXPORT_SYMBOL(llog_cat_reverse_process);
-int llog_cat_set_first_idx(struct llog_handle *cathandle, int index)
+static int llog_cat_set_first_idx(struct llog_handle *cathandle, int idx)
{
- struct llog_log_hdr *llh = cathandle->lgh_hdr;
- int i, bitmap_size, idx;
- ENTRY;
+ struct llog_log_hdr *llh = cathandle->lgh_hdr;
+ int bitmap_size;
- bitmap_size = LLOG_BITMAP_SIZE(llh);
- if (llh->llh_cat_idx == (index - 1)) {
- idx = llh->llh_cat_idx + 1;
- llh->llh_cat_idx = idx;
- if (idx == cathandle->lgh_last_idx)
- goto out;
- for (i = (index + 1) % bitmap_size;
- i != cathandle->lgh_last_idx;
- i = (i + 1) % bitmap_size) {
- if (!ext2_test_bit(i, llh->llh_bitmap)) {
- idx = llh->llh_cat_idx + 1;
- llh->llh_cat_idx = idx;
- } else if (i == 0) {
- llh->llh_cat_idx = 0;
- } else {
- break;
- }
- }
-out:
- CDEBUG(D_RPCTRACE, "set catlog "DOSTID" first idx %u\n",
- POSTID(&cathandle->lgh_id.lgl_oi), llh->llh_cat_idx);
+ ENTRY;
+
+ bitmap_size = LLOG_HDR_BITMAP_SIZE(llh);
+ /*
+ * The llh_cat_idx equals to the first used index minus 1
+ * so if we canceled the first index then llh_cat_idx
+ * must be renewed.
+ */
+ if (llh->llh_cat_idx == (idx - 1)) {
+ llh->llh_cat_idx = idx;
+
+ do {
+ idx = (idx + 1) % bitmap_size;
+ if (!ext2_test_bit(idx, LLOG_HDR_BITMAP(llh))) {
+ /* update llh_cat_idx for each unset bit,
+ * expecting the*/
+ llh->llh_cat_idx = idx;
+ } else if (idx == 0) {
+ /* skip header bit */
+ continue;
+ } else {
+ /* the first index is found */
+ break;
+ }
+ } while (idx != cathandle->lgh_last_idx);
+
+ CDEBUG(D_RPCTRACE, "Set catlog "DOSTID" first idx %u,"
+ " (last_idx %u)\n", POSTID(&cathandle->lgh_id.lgl_oi),
+ llh->llh_cat_idx, cathandle->lgh_last_idx);
}
RETURN(0);
down_write(&cathandle->lgh_lock);
if (cathandle->u.chd.chd_current_log == loghandle)
cathandle->u.chd.chd_current_log = NULL;
- cfs_list_del_init(&loghandle->u.phd.phd_entry);
+ list_del_init(&loghandle->u.phd.phd_entry);
up_write(&cathandle->lgh_lock);
LASSERT(index == loghandle->u.phd.phd_cookie.lgc_index);
/* llog was opened and keep in a list, close it now */
llog_close(env, loghandle);
}
+
+ /* do not attempt to cleanup on-disk llog if on client side */
+ if (cathandle->lgh_obj == NULL)
+ return 0;
+
/* remove plain llog entry from catalog by index */
llog_cat_set_first_idx(cathandle, index);
rc = llog_cancel_rec(env, cathandle, index);
return rc;
}
-int cat_cancel_cb(const struct lu_env *env, struct llog_handle *cathandle,
- struct llog_rec_hdr *rec, void *data)
-{
- struct llog_logid_rec *lir = (struct llog_logid_rec *)rec;
- struct llog_handle *loghandle;
- struct llog_log_hdr *llh;
- int rc;
-
- ENTRY;
-
- if (rec->lrh_type != LLOG_LOGID_MAGIC) {
- CERROR("invalid record in catalog\n");
- RETURN(-EINVAL);
- }
-
- CDEBUG(D_HA, "processing log "DOSTID":%x at index %u of catalog "
- DOSTID"\n", POSTID(&lir->lid_id.lgl_oi), lir->lid_id.lgl_ogen,
- rec->lrh_index, POSTID(&cathandle->lgh_id.lgl_oi));
-
- rc = llog_cat_id2handle(env, cathandle, &loghandle, &lir->lid_id);
- if (rc) {
- CERROR("%s: cannot find handle for llog "DOSTID": %d\n",
- cathandle->lgh_ctxt->loc_obd->obd_name,
- POSTID(&lir->lid_id.lgl_oi), rc);
- if (rc == -ENOENT || rc == -ESTALE) {
- /* remove index from catalog */
- llog_cat_cleanup(env, cathandle, NULL, rec->lrh_index);
- }
- RETURN(rc);
- }
-
- llh = loghandle->lgh_hdr;
- if ((llh->llh_flags & LLOG_F_ZAP_WHEN_EMPTY) &&
- (llh->llh_count == 1)) {
- rc = llog_destroy(env, loghandle);
- if (rc)
- CERROR("%s: fail to destroy empty log: rc = %d\n",
- loghandle->lgh_ctxt->loc_obd->obd_name, rc);
-
- llog_cat_cleanup(env, cathandle, loghandle,
- loghandle->u.phd.phd_cookie.lgc_index);
- }
- llog_handle_put(loghandle);
-
- RETURN(rc);
-}
-EXPORT_SYMBOL(cat_cancel_cb);
-
/* helper to initialize catalog llog and process it to cancel */
int llog_cat_init_and_process(const struct lu_env *env,
struct llog_handle *llh)
if (rc)
RETURN(rc);
- rc = llog_process_or_fork(env, llh, cat_cancel_cb, NULL, NULL, false);
- if (rc)
- CERROR("%s: llog_process() with cat_cancel_cb failed: rc = "
- "%d\n", llh->lgh_ctxt->loc_obd->obd_name, rc);
RETURN(0);
}
EXPORT_SYMBOL(llog_cat_init_and_process);
-