Ejemplo n.º 1
0
static int llog_remove_log(const struct lu_env *env, struct llog_handle *cat,
			   struct llog_logid *logid)
{
	struct llog_handle	*log;
	int			 rc;

	ENTRY;

	rc = llog_cat_id2handle(env, cat, &log, logid);
	if (rc) {
		CDEBUG(D_IOCTL, "cannot find log #"DOSTID"#%08x\n",
		       POSTID(&logid->lgl_oi), logid->lgl_ogen);
		RETURN(-ENOENT);
	}

	rc = llog_destroy(env, log);
	if (rc) {
		CDEBUG(D_IOCTL, "cannot destroy log\n");
		GOTO(out, rc);
	}
	llog_cat_cleanup(env, cat, log, log->u.phd.phd_cookie.lgc_index);
out:
	llog_handle_put(log);
	RETURN(rc);

}
Ejemplo n.º 2
0
static int llog_remove_log(struct llog_handle *cat, struct llog_logid *logid)
{
        struct llog_handle *log;
        int rc, index = 0;

        ENTRY;
        cfs_down_write(&cat->lgh_lock);
        rc = llog_cat_id2handle(cat, &log, logid);
        if (rc) {
                CDEBUG(D_IOCTL, "cannot find log #"LPX64"#"LPX64"#%08x\n",
                       logid->lgl_oid, logid->lgl_oseq, logid->lgl_ogen);
                GOTO(out, rc = -ENOENT);
        }

        index = log->u.phd.phd_cookie.lgc_index;
        LASSERT(index);
        rc = llog_destroy(log);
        if (rc) {
                CDEBUG(D_IOCTL, "cannot destroy log\n");
                GOTO(out, rc);
        }
        llog_cat_set_first_idx(cat, index);
        rc = llog_cancel_rec(cat, index);
out:
        llog_free_handle(log);
        cfs_up_write(&cat->lgh_lock);
        RETURN(rc);

}
Ejemplo n.º 3
0
/**
 * 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);
}
Ejemplo n.º 4
0
Archivo: llog.c Proyecto: Lezval/lustre
/* returns negative on error; 0 if success; 1 if success & log destroyed */
int llog_cancel_rec(const struct lu_env *env, struct llog_handle *loghandle,
		    int index)
{
        struct llog_log_hdr *llh = loghandle->lgh_hdr;
        int rc = 0;
        ENTRY;

        CDEBUG(D_RPCTRACE, "Canceling %d in log "DOSTID"\n",
               index, POSTID(&loghandle->lgh_id.lgl_oi));

        if (index == 0) {
                CERROR("Can't cancel index 0 which is header\n");
                RETURN(-EINVAL);
        }

	spin_lock(&loghandle->lgh_hdr_lock);
	if (!ext2_clear_bit(index, llh->llh_bitmap)) {
		spin_unlock(&loghandle->lgh_hdr_lock);
		CDEBUG(D_RPCTRACE, "Catalog index %u already clear?\n", index);
		RETURN(-ENOENT);
	}

	llh->llh_count--;

	if ((llh->llh_flags & LLOG_F_ZAP_WHEN_EMPTY) &&
	    (llh->llh_count == 1) &&
	    (loghandle->lgh_last_idx == (LLOG_BITMAP_BYTES * 8) - 1)) {
		spin_unlock(&loghandle->lgh_hdr_lock);
		rc = llog_destroy(env, loghandle);
		if (rc < 0) {
			CERROR("%s: can't destroy empty llog #"DOSTID
			       "#%08x: rc = %d\n",
			       loghandle->lgh_ctxt->loc_obd->obd_name,
			       POSTID(&loghandle->lgh_id.lgl_oi),
			       loghandle->lgh_id.lgl_ogen, rc);
			GOTO(out_err, rc);
		}
		RETURN(1);
	}
	spin_unlock(&loghandle->lgh_hdr_lock);

	rc = llog_write(env, loghandle, &llh->llh_hdr, NULL, 0, NULL, 0);
	if (rc < 0) {
		CERROR("%s: fail to write header for llog #"DOSTID
		       "#%08x: rc = %d\n",
		       loghandle->lgh_ctxt->loc_obd->obd_name,
		       POSTID(&loghandle->lgh_id.lgl_oi),
		       loghandle->lgh_id.lgl_ogen, rc);
		GOTO(out_err, rc);
	}
	RETURN(0);
out_err:
	spin_lock(&loghandle->lgh_hdr_lock);
	ext2_set_bit(index, llh->llh_bitmap);
	llh->llh_count++;
	spin_unlock(&loghandle->lgh_hdr_lock);
	return rc;
}
Ejemplo n.º 5
0
/* -------------------------------------------------------------------------
 * Tests above, boring obd functions below
 * ------------------------------------------------------------------------- */
static int llog_run_tests(const struct lu_env *env, struct obd_device *obd)
{
	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;
}
Ejemplo n.º 6
0
int llog_origin_handle_destroy(struct ptlrpc_request *req)
{
        struct obd_export    *exp = req->rq_export;
        struct obd_device    *obd = exp->exp_obd;
        struct obd_device    *disk_obd;
        struct llog_handle   *loghandle;
        struct llogd_body    *body;
        struct lvfs_run_ctxt  saved;
        struct llog_logid    *logid = NULL;
        struct llog_ctxt     *ctxt;
        int                   rc;
        ENTRY;

        body = req_capsule_client_get(&req->rq_pill, &RMF_LLOGD_BODY);
        if (body == NULL)
                RETURN(-EFAULT);

        if (body->lgd_logid.lgl_oid > 0)
                logid = &body->lgd_logid;

        ctxt = llog_get_context(obd, body->lgd_ctxt_idx);
        if (ctxt == NULL)
                RETURN(-ENODEV);

        disk_obd = ctxt->loc_exp->exp_obd;
        push_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL);

        rc = llog_create(ctxt, &loghandle, logid, NULL);
        if (rc)
                GOTO(out_pop, rc);

        rc = req_capsule_server_pack(&req->rq_pill);
        if (rc)
                GOTO(out_close, rc = -ENOMEM);

        body = req_capsule_server_get(&req->rq_pill, &RMF_LLOGD_BODY);
        body->lgd_logid = loghandle->lgh_id;
        rc = llog_init_handle(loghandle, LLOG_F_IS_PLAIN, NULL);
        if (rc)
                GOTO(out_close, rc);
        rc = llog_destroy(loghandle);
        if (rc)
                GOTO(out_close, rc);
        llog_free_handle(loghandle);
        GOTO(out_close, rc);
out_close:
        if (rc)
                llog_close(loghandle);
out_pop:
        pop_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL);
        llog_ctxt_put(ctxt);
        return rc;
}
Ejemplo n.º 7
0
/* Test named-log reopen; returns opened log on success */
static int llog_test_2(struct obd_device *obd, char *name,
                       struct llog_handle **llh)
{
        struct llog_ctxt *ctxt = llog_get_context(obd, LLOG_TEST_ORIG_CTXT);
        int rc;
        ENTRY;

        CWARN("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);
                GOTO(out, rc);
        }
        llog_init_handle(*llh, LLOG_F_IS_PLAIN, &uuid);

        if ((rc = verify_handle("2", *llh, 1)))
                GOTO(out, rc);
#if 0
        CWARN("2b: create a log without specified NAME & LOGID\n");
        rc = llog_create(ctxt, &loghandle, NULL, NULL);
        if (rc) {
                CERROR("2b: create log failed\n");
                GOTO(out, rc);
        }
        llog_init_handle(loghandle, LLOG_F_IS_PLAIN, &uuid);
        logid = loghandle->lgh_id;
        llog_close(loghandle);

        CWARN("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");
                GOTO(out, rc);
        }
        llog_init_handle(loghandle, LLOG_F_IS_PLAIN, &uuid);

        CWARN("2b: destroy this log\n");
        rc = llog_destroy(loghandle);
        if (rc) {
                CERROR("2b: destroy log failed\n");
                GOTO(out, rc);
        }
        llog_free_handle(loghandle);
#endif
out:
        llog_ctxt_put(ctxt);

        RETURN(rc);
}
Ejemplo n.º 8
0
static int llog_test_7(struct obd_device *obd)
{
        struct llog_ctxt *ctxt = llog_get_context(obd, LLOG_TEST_ORIG_CTXT);
        struct llog_handle *llh;
        struct llog_create_rec lcr;
        char name[10];
        int rc;
        ENTRY;

        sprintf(name, "%x", llog_test_rand+2);
        CWARN("7: create a log with name: %s\n", name);
        LASSERT(ctxt);

        rc = llog_create(ctxt, &llh, NULL, name);
        if (rc) {
                CERROR("7: llog_create with name %s failed: %d\n", name, rc);
                GOTO(ctxt_release, rc);
        }
        llog_init_handle(llh, LLOG_F_IS_PLAIN, &uuid);

        lcr.lcr_hdr.lrh_len = lcr.lcr_tail.lrt_len = sizeof(lcr);
        lcr.lcr_hdr.lrh_type = OST_SZ_REC;
        rc = llog_write_rec(llh,  &lcr.lcr_hdr, NULL, 0, NULL, -1);
        if (rc) {
                CERROR("7: write one log record failed: %d\n", rc);
                GOTO(ctxt_release, rc);
        }

        rc = llog_destroy(llh);
        if (rc)
                CERROR("7: llog_destroy failed: %d\n", rc);
        else
                llog_free_handle(llh);
ctxt_release:
        llog_ctxt_put(ctxt);
        RETURN(rc);
}
Ejemplo n.º 9
0
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;

	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, NULL, 0,
				NULL, -1);
		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) {
		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;
}
Ejemplo n.º 10
0
/* 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;
}
Ejemplo n.º 11
0
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);
}
Ejemplo n.º 12
0
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;
}