-/**
- * lockdep markers for nested struct llog_handle::lgh_lock locking.
- */
-enum {
- LLOGH_CAT,
- LLOGH_LOG
-};
-
-/** Return the currently active log handle. If the current log handle doesn't
- * have enough space left for the current record, start a new one.
- *
- * If reclen is 0, we only want to know what the currently active log is,
- * otherwise we get a lock on this log so nobody can steal our space.
- *
- * Assumes caller has already pushed us into the kernel context and is locking.
- *
- * NOTE: loghandle is write-locked upon successful return
- */
-static struct llog_handle *llog_cat_current_log(struct llog_handle *cathandle,
- struct thandle *th)
-{
- struct llog_handle *loghandle = NULL;
-
- down_read_nested(&cathandle->lgh_lock, LLOGH_CAT);
- loghandle = cathandle->u.chd.chd_current_log;
- if (loghandle) {
- struct llog_log_hdr *llh;
-
- down_write_nested(&loghandle->lgh_lock, LLOGH_LOG);
- llh = loghandle->lgh_hdr;
- if (llh == NULL ||
- loghandle->lgh_last_idx < LLOG_BITMAP_SIZE(llh) - 1) {
- up_read(&cathandle->lgh_lock);
- return loghandle;
- } else {
- up_write(&loghandle->lgh_lock);
- }
- }
- up_read(&cathandle->lgh_lock);
-
- /* time to use next log */
-
- /* first, we have to make sure the state hasn't changed */
- down_write_nested(&cathandle->lgh_lock, LLOGH_CAT);
- loghandle = cathandle->u.chd.chd_current_log;
- if (loghandle) {
- struct llog_log_hdr *llh;
-
- down_write_nested(&loghandle->lgh_lock, LLOGH_LOG);
- llh = loghandle->lgh_hdr;
- LASSERT(llh);
- if (loghandle->lgh_last_idx < LLOG_BITMAP_SIZE(llh) - 1) {
- up_write(&cathandle->lgh_lock);
- return loghandle;
- } else {
- up_write(&loghandle->lgh_lock);
- }
- }
-
- CDEBUG(D_INODE, "use next log\n");
-
- loghandle = cathandle->u.chd.chd_next_log;
- cathandle->u.chd.chd_current_log = loghandle;
- cathandle->u.chd.chd_next_log = NULL;
- down_write_nested(&loghandle->lgh_lock, LLOGH_LOG);
- up_write(&cathandle->lgh_lock);
- LASSERT(loghandle);
- return loghandle;
-}
-
-/* Add a single record to the recovery log(s) using a catalog
- * Returns as llog_write_record
- *
- * Assumes caller has already pushed us into the kernel context.
- */
-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 llog_handle *loghandle;
- int rc;
-
- LASSERT(rec->lrh_len <= LLOG_CHUNK_SIZE);
- loghandle = llog_cat_current_log(cathandle, th);
- LASSERT(!IS_ERR(loghandle));
-
- /* loghandle is already locked by llog_cat_current_log() for us */
- if (!llog_exist(loghandle)) {
- rc = llog_cat_new_log(env, cathandle, loghandle, th);
- if (rc < 0) {
- up_write(&loghandle->lgh_lock);
- return rc;
- }
- }
- /* now let's try to add the record */
- rc = llog_write_rec(env, loghandle, rec, reccookie, 1, buf, -1, th);
- if (rc < 0)
- CDEBUG_LIMIT(rc == -ENOSPC ? D_HA : D_ERROR,
- "llog_write_rec %d: lh=%p\n", rc, loghandle);
- up_write(&loghandle->lgh_lock);
- if (rc == -ENOSPC) {
- /* try to use next log */
- loghandle = llog_cat_current_log(cathandle, th);
- LASSERT(!IS_ERR(loghandle));
- /* new llog can be created concurrently */
- if (!llog_exist(loghandle)) {
- rc = llog_cat_new_log(env, cathandle, loghandle, th);
- if (rc < 0) {
- up_write(&loghandle->lgh_lock);
- return rc;
- }
- }
- /* now let's try to add the record */
- rc = llog_write_rec(env, loghandle, rec, reccookie, 1, buf,
- -1, th);
- if (rc < 0)
- CERROR("llog_write_rec %d: lh=%p\n", rc, loghandle);
- up_write(&loghandle->lgh_lock);
- }
-
- return rc;
-}
-EXPORT_SYMBOL(llog_cat_add_rec);
-
-int llog_cat_declare_add_rec(const struct lu_env *env,
- struct llog_handle *cathandle,
- struct llog_rec_hdr *rec, struct thandle *th)
-{
- struct llog_handle *loghandle, *next;
- int rc = 0;
-
- if (cathandle->u.chd.chd_current_log == NULL) {
- /* declare new plain llog */
- down_write(&cathandle->lgh_lock);
- if (cathandle->u.chd.chd_current_log == NULL) {
- rc = llog_open(env, cathandle->lgh_ctxt, &loghandle,
- NULL, NULL, LLOG_OPEN_NEW);
- if (rc == 0) {
- cathandle->u.chd.chd_current_log = loghandle;
- list_add_tail(&loghandle->u.phd.phd_entry,
- &cathandle->u.chd.chd_head);
- }
- }
- up_write(&cathandle->lgh_lock);
- } else if (cathandle->u.chd.chd_next_log == NULL) {
- /* declare next plain llog */
- down_write(&cathandle->lgh_lock);
- if (cathandle->u.chd.chd_next_log == NULL) {
- rc = llog_open(env, cathandle->lgh_ctxt, &loghandle,
- NULL, NULL, LLOG_OPEN_NEW);
- if (rc == 0) {
- cathandle->u.chd.chd_next_log = loghandle;
- list_add_tail(&loghandle->u.phd.phd_entry,
- &cathandle->u.chd.chd_head);
- }
- }
- up_write(&cathandle->lgh_lock);
- }
- if (rc)
- goto out;
-
- 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;
- llog_declare_write_rec(env, cathandle, NULL, -1, th);
- }
- /* declare records in the llogs */
- rc = llog_declare_write_rec(env, cathandle->u.chd.chd_current_log,
- rec, -1, th);
- if (rc)
- goto out;
-
- next = cathandle->u.chd.chd_next_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, 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_ctxt *ctxt;
- struct dt_device *dt;
- struct thandle *th = NULL;
- int rc;
-
- ctxt = cathandle->lgh_ctxt;
- LASSERT(ctxt);
- LASSERT(ctxt->loc_exp);
-
- if (cathandle->lgh_obj != NULL) {
- dt = ctxt->loc_exp->exp_obd->obd_lvfs_ctxt.dt;
- LASSERT(dt);
-
- th = dt_trans_create(env, dt);
- if (IS_ERR(th))
- return PTR_ERR(th);
-
- rc = llog_cat_declare_add_rec(env, cathandle, rec, th);
- if (rc)
- goto out_trans;
-
- rc = dt_trans_start_local(env, dt, th);
- if (rc)
- goto out_trans;
- rc = llog_cat_add_rec(env, cathandle, rec, reccookie, buf, th);
-out_trans:
- dt_trans_stop(env, dt, th);
- } else { /* lvfs compat code */
- LASSERT(cathandle->lgh_file != NULL);
- rc = llog_cat_declare_add_rec(env, cathandle, rec, th);
- if (rc == 0)
- rc = llog_cat_add_rec(env, cathandle, rec, reccookie,
- buf, th);
- }
- return rc;
-}
-EXPORT_SYMBOL(llog_cat_add);
-
-/* For each cookie in the cookie array, we clear the log in-use bit and either:
- * - the log is empty, so mark it free in the catalog header and delete it
- * - the log is not empty, just write out the log header
- *
- * The cookies may be in different log files, so we need to get new logs
- * each time.
- *
- * Assumes caller has already pushed us into the kernel context.
- */
-int llog_cat_cancel_records(const struct lu_env *env,
- struct llog_handle *cathandle, int count,
- struct llog_cookie *cookies)
-{
- int i, index, rc = 0, failed = 0;
-
- for (i = 0; i < count; i++, cookies++) {
- struct llog_handle *loghandle;
- struct llog_logid *lgl = &cookies->lgc_lgl;
- int lrc;
-
- rc = llog_cat_id2handle(env, cathandle, &loghandle, lgl);
- if (rc) {
- CERROR("%s: cannot find handle for llog "DOSTID": %d\n",
- cathandle->lgh_ctxt->loc_obd->obd_name,
- POSTID(&lgl->lgl_oi), rc);
- failed++;
- continue;
- }
-
- lrc = llog_cancel_rec(env, loghandle, cookies->lgc_index);
- if (lrc == 1) { /* log has been destroyed */
- index = loghandle->u.phd.phd_cookie.lgc_index;
- rc = llog_cat_cleanup(env, cathandle, loghandle,
- index);
- } else if (lrc == -ENOENT) {
- if (rc == 0) /* ENOENT shouldn't rewrite any error */
- rc = lrc;
- } else if (lrc < 0) {
- failed++;
- rc = lrc;
- }
- llog_handle_put(loghandle);
- }
- if (rc)
- CERROR("%s: fail to cancel %d of %d llog-records: rc = %d\n",
- cathandle->lgh_ctxt->loc_obd->obd_name, failed, count,
- rc);
-
- return rc;
-}
-EXPORT_SYMBOL(llog_cat_cancel_records);
-