Beispiel #1
0
static int mds_cmd_cleanup(struct obd_device *obd)
{
        struct mds_obd *mds = &obd->u.mds;
        struct lvfs_run_ctxt saved;
        int rc = 0;
        ENTRY;

        mds->mds_lov_exp = NULL;

        if (obd->obd_fail)
                LCONSOLE_WARN("%s: shutting down for failover; client state "
                              "will be preserved.\n", obd->obd_name);

        if (strncmp(obd->obd_name, MDD_OBD_NAME, strlen(MDD_OBD_NAME)))
                RETURN(0);

        push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);

        mds_lov_destroy_objids(obd);

        if (mds->mds_objects_dir != NULL) {
                l_dput(mds->mds_objects_dir);
                mds->mds_objects_dir = NULL;
        }

        dput(mds->mds_fid_de);
        LL_DQUOT_OFF(obd->u.obt.obt_sb);
        shrink_dcache_sb(mds->mds_obt.obt_sb);
        fsfilt_put_ops(obd->obd_fsops);

        pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
        RETURN(rc);
}
Beispiel #2
0
static int target_quotacheck_thread(void *data)
{
        struct quotacheck_thread_args *qta = data;
        struct obd_export *exp;
        struct obd_device *obd;
        struct obd_quotactl *oqctl;
        struct lvfs_run_ctxt saved;
        int rc;

        cfs_daemonize_ctxt("quotacheck");

        exp = qta->qta_exp;
        obd = qta->qta_obd;
        oqctl = &qta->qta_oqctl;

        push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);

        rc = fsfilt_quotacheck(obd, qta->qta_sb, oqctl);
        if (rc)
                CERROR("%s: fsfilt_quotacheck: %d\n", obd->obd_name, rc);

        pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);

        rc = target_quotacheck_callback(exp, oqctl);
        class_export_put(exp);
        cfs_up(qta->qta_sem);
        OBD_FREE_PTR(qta);
        return rc;
}
Beispiel #3
0
int llog_origin_handle_create(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;
        char                 *name = NULL;
        int                   rc, rc2;
        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;

        if (req_capsule_field_present(&req->rq_pill, &RMF_NAME, RCL_CLIENT)) {
                name = req_capsule_client_get(&req->rq_pill, &RMF_NAME);
                if (name == NULL)
                        RETURN(-EFAULT);
                CDEBUG(D_INFO, "%s: opening log %s\n", obd->obd_name, name);
        }

        ctxt = llog_get_context(obd, body->lgd_ctxt_idx);
        if (ctxt == NULL) {
                CDEBUG(D_WARNING, "%s: no ctxt. group=%p idx=%d name=%s\n",
                       obd->obd_name, &obd->obd_olg, body->lgd_ctxt_idx, name);
                RETURN(-ENODEV);
        }
        disk_obd = ctxt->loc_exp->exp_obd;
        push_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL);

        rc = llog_create(ctxt, &loghandle, logid, name);
        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;

        GOTO(out_close, rc);
out_close:
        rc2 = llog_close(loghandle);
        if (!rc)
                rc = rc2;
out_pop:
        pop_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL);
        llog_ctxt_put(ctxt);
        return rc;
}
Beispiel #4
0
static int llog_catinfo_config(struct obd_device *obd, char *buf, int buf_len,
                               char *client)
{
        struct mds_obd       *mds = &obd->u.mds;
        struct llog_ctxt     *ctxt = llog_get_context(obd, LLOG_CONFIG_ORIG_CTXT);
        struct lvfs_run_ctxt  saved;
        struct llog_handle   *handle = NULL;
        char                  name[4][64];
        int                   rc, i, l, remains = buf_len;
        char                 *out = buf;
        ENTRY;

        if (ctxt == NULL || mds == NULL)
                GOTO(release_ctxt, rc = -ENODEV);

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

        sprintf(name[0], "%s", mds->mds_profile);
        sprintf(name[1], "%s-clean", mds->mds_profile);
        sprintf(name[2], "%s", client);
        sprintf(name[3], "%s-clean", client);

        for (i = 0; i < 4; i++) {
                int index, uncanceled = 0;
                rc = llog_create(ctxt, &handle, NULL, name[i]);
                if (rc)
                        GOTO(out_pop, rc);
                rc = llog_init_handle(handle, 0, NULL);
                if (rc) {
                        llog_close(handle);
                        GOTO(out_pop, rc = -ENOENT);
                }

                for (index = 1; index < (LLOG_BITMAP_BYTES * 8); index ++) {
                        if (ext2_test_bit(index, handle->lgh_hdr->llh_bitmap))
                                uncanceled++;
                }

                l = snprintf(out, remains, "[Log Name]: %s\nLog Size: %llu\n"
                             "Last Index: %d\nUncanceled Records: %d\n\n",
                             name[i],
                             i_size_read(handle->lgh_file->f_dentry->d_inode),
                             handle->lgh_last_idx, uncanceled);
                out += l;
                remains -= l;

                llog_close(handle);
                if (remains <= 0)
                        break;
        }
        GOTO(out_pop, rc);
out_pop:
        pop_ctxt(&saved, &ctxt->loc_exp->exp_obd->obd_lvfs_ctxt, NULL);
release_ctxt:
        llog_ctxt_put(ctxt);
        return rc;
}
Beispiel #5
0
/* -------------------------------------------------------------------------
 * Tests above, boring obd functions below
 * ------------------------------------------------------------------------- */
static int llog_run_tests(struct obd_device *obd)
{
        struct llog_handle *llh;
        struct lvfs_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_lvfs_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);

        rc = llog_test_7(obd);
        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_lvfs_ctxt, NULL);
        }
        llog_ctxt_put(ctxt);
        return rc;
}
Beispiel #6
0
int mgs_fs_setup(struct obd_device *obd, struct vfsmount *mnt)
{
        struct mgs_obd *mgs = &obd->u.mgs;
        struct lvfs_run_ctxt saved;
        struct dentry *dentry;
        int rc;
        ENTRY;

        /* FIXME what's this?  Do I need it? */
        rc = cfs_cleanup_group_info();
        if (rc)
                RETURN(rc);

        mgs->mgs_vfsmnt = mnt;
        mgs->mgs_sb = mnt->mnt_root->d_inode->i_sb;

        rc = fsfilt_setup(obd, mgs->mgs_sb);
        if (rc)
                RETURN(rc);

        OBD_SET_CTXT_MAGIC(&obd->obd_lvfs_ctxt);
        obd->obd_lvfs_ctxt.pwdmnt = mnt;
        obd->obd_lvfs_ctxt.pwd = mnt->mnt_root;
        obd->obd_lvfs_ctxt.fs = get_ds();
        obd->obd_lvfs_ctxt.cb_ops = mgs_lvfs_ops;

        push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);

        /* Setup the configs dir */
        dentry = simple_mkdir(cfs_fs_pwd(current->fs), mnt, MOUNT_CONFIGS_DIR, 0777, 1);
        if (IS_ERR(dentry)) {
                rc = PTR_ERR(dentry);
                CERROR("cannot create %s directory: rc = %d\n",
                       MOUNT_CONFIGS_DIR, rc);
                GOTO(err_pop, rc);
        }
        mgs->mgs_configs_dir = dentry;

        /* create directory to store nid table versions */
        dentry = simple_mkdir(cfs_fs_pwd(current->fs), mnt, MGS_NIDTBL_DIR,
                              0777, 1);
        if (IS_ERR(dentry)) {
                rc = PTR_ERR(dentry);
                CERROR("cannot create %s directory: rc = %d\n",
                       MOUNT_CONFIGS_DIR, rc);
                GOTO(err_pop, rc);
        } else {
                dput(dentry);
        }

err_pop:
        pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
        return rc;
}
Beispiel #7
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;
}
Beispiel #8
0
int llog_origin_handle_read_header(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 llog_log_hdr  *hdr;
        struct lvfs_run_ctxt  saved;
        struct llog_ctxt     *ctxt;
        __u32                 flags;
        int                   rc, rc2;
        ENTRY;

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

        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, &body->lgd_logid, NULL);
        if (rc)
                GOTO(out_pop, rc);

        /*
         * llog_init_handle() reads the llog header
         */
        flags = body->lgd_llh_flags;
        rc = llog_init_handle(loghandle, flags, NULL);
        if (rc)
                GOTO(out_close, rc);

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

        hdr = req_capsule_server_get(&req->rq_pill, &RMF_LLOG_LOG_HDR);
        *hdr = *loghandle->lgh_hdr;
        GOTO(out_close, rc);
out_close:
        rc2 = llog_close(loghandle);
        if (!rc)
                rc = rc2;
out_pop:
        pop_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL);
        llog_ctxt_put(ctxt);
        return rc;
}
Beispiel #9
0
/*
 * generic_quota_on is very lazy and tolerant about current quota settings
 * @global means to turn on quotas on each OST additionally to local quotas;
 * should not be called from filter_quota_ctl on MDS nodes (as it starts
 * admin quotas on MDS nodes).
 */
int generic_quota_on(struct obd_device *obd, struct obd_quotactl *oqctl, int global)
{
        struct obd_device_target *obt = &obd->u.obt;
        struct lvfs_run_ctxt saved;
        int id, is_master, rc = 0, local; /* means we need a local quotaon */

        cfs_down(&obt->obt_quotachecking);
        push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
        id = UGQUOTA2LQC(oqctl->qc_type);
        local = (obt->obt_qctxt.lqc_flags & id) != id;

        oqctl->qc_cmd = Q_QUOTAON;
        oqctl->qc_id = obt->obt_qfmt;

        is_master = !strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME);
        if (is_master) {
                cfs_down_write(&obd->u.mds.mds_qonoff_sem);
                if (local) {
                        /* turn on cluster wide quota */
                        rc = mds_admin_quota_on(obd, oqctl);
                        if (rc && rc != -ENOENT)
                                CERROR("%s: %s admin quotaon failed. rc=%d\n",
                                       obd->obd_name, global ? "global":"local",
                                       rc);
                }
        }

        if (rc == 0) {
                if (local) {
                        rc = fsfilt_quotactl(obd, obt->obt_sb, oqctl);
                        if (rc) {
                                if (rc != -ENOENT)
                                        CERROR("%s: %s quotaon failed with"
                                               " rc=%d\n", obd->obd_name,
                                               global ? "global" : "local", rc);
                        } else {
                                obt->obt_qctxt.lqc_flags |= UGQUOTA2LQC(oqctl->qc_type);
                                build_lqs(obd);
                        }
                }

                if (rc == 0 && global && is_master)
                        rc = obd_quotactl(obd->u.mds.mds_lov_exp, oqctl);
        }

        if (is_master)
                cfs_up_write(&obd->u.mds.mds_qonoff_sem);

        pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
        cfs_up(&obt->obt_quotachecking);

        return rc;
}
Beispiel #10
0
/* reads the catalog list */
int llog_get_cat_list(struct obd_device *disk_obd,
                      char *name, int idx, int count, struct llog_catid *idarray)
{
        struct lvfs_run_ctxt saved;
        struct l_file *file;
        int rc, rc1 = 0;
        int size = sizeof(*idarray) * count;
        loff_t off = idx *  sizeof(*idarray);
        ENTRY;

        if (!count)
                RETURN(0);

        push_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL);
        file = filp_open(name, O_RDWR | O_CREAT | O_LARGEFILE, 0700);
        if (!file || IS_ERR(file)) {
                rc = PTR_ERR(file);
                CERROR("OBD filter: cannot open/create %s: rc = %d\n",
                       name, rc);
                GOTO(out, rc);
        }

        if (!S_ISREG(file->f_dentry->d_inode->i_mode)) {
                CERROR("%s is not a regular file!: mode = %o\n", name,
                       file->f_dentry->d_inode->i_mode);
                GOTO(out, rc = -ENOENT);
        }

        CDEBUG(D_CONFIG, "cat list: disk size=%d, read=%d\n",
               (int)i_size_read(file->f_dentry->d_inode), size);

        /* read for new ost index or for empty file */
        memset(idarray, 0, size);
        if (i_size_read(file->f_dentry->d_inode) < off)
                GOTO(out, rc = 0);

        rc = fsfilt_read_record(disk_obd, file, idarray, size, &off);
        if (rc) {
                CERROR("OBD filter: error reading %s: rc %d\n", name, rc);
                GOTO(out, rc);
        }

        EXIT;
 out:
        pop_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL);
        if (file && !IS_ERR(file))
                rc1 = filp_close(file, 0);
        if (rc == 0)
                rc = rc1;
        return rc;
}
Beispiel #11
0
/* writes the cat list */
int llog_put_cat_list(struct obd_device *disk_obd,
                      char *name, int idx, int count, struct llog_catid *idarray)
{
        struct lvfs_run_ctxt saved;
        struct l_file *file;
        int rc, rc1 = 0;
        int size = sizeof(*idarray) * count;
        loff_t off = idx * sizeof(*idarray);

        if (!count)
                GOTO(out1, rc = 0);

        push_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL);
        file = filp_open(name, O_RDWR | O_CREAT | O_LARGEFILE, 0700);
        if (!file || IS_ERR(file)) {
                rc = PTR_ERR(file);
                CERROR("OBD filter: cannot open/create %s: rc = %d\n",
                       name, rc);
                GOTO(out, rc);
        }

        if (!S_ISREG(file->f_dentry->d_inode->i_mode)) {
                CERROR("%s is not a regular file!: mode = %o\n", name,
                       file->f_dentry->d_inode->i_mode);
                GOTO(out, rc = -ENOENT);
        }

        rc = fsfilt_write_record(disk_obd, file, idarray, size, &off, 1);
        if (rc) {
                CDEBUG(D_INODE,"OBD filter: error writeing %s: rc %d\n",
                       name, rc);
                GOTO(out, rc);
        }

out:
        pop_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL);
        if (file && !IS_ERR(file))
                rc1 = filp_close(file, 0);

        if (rc == 0)
                rc = rc1;
out1:
        RETURN(rc);
}
Beispiel #12
0
int mgs_fs_cleanup(struct obd_device *obd)
{
        struct mgs_obd *mgs = &obd->u.mgs;
        struct lvfs_run_ctxt saved;
        int rc = 0;

        class_disconnect_exports(obd); /* cleans up client info too */

        push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);

        if (mgs->mgs_configs_dir) {
                l_dput(mgs->mgs_configs_dir);
                mgs->mgs_configs_dir = NULL;
        }

        shrink_dcache_sb(mgs->mgs_sb);

        pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);

        return rc;
}
Beispiel #13
0
int llog_origin_handle_cancel(struct ptlrpc_request *req)
{
        struct obd_device *obd = req->rq_export->exp_obd;
        int num_cookies, rc = 0, err, i, failed = 0;
        struct obd_device *disk_obd;
        struct llog_cookie *logcookies;
        struct llog_ctxt *ctxt = NULL;
        struct lvfs_run_ctxt saved;
        struct llog_handle *cathandle;
        struct inode *inode;
        void *handle;
        ENTRY;

        logcookies = req_capsule_client_get(&req->rq_pill, &RMF_LOGCOOKIES);
        num_cookies = req_capsule_get_size(&req->rq_pill, &RMF_LOGCOOKIES,
                                           RCL_CLIENT) / sizeof(*logcookies);
        if (logcookies == NULL || num_cookies == 0) {
                DEBUG_REQ(D_HA, req, "No llog cookies sent");
                RETURN(-EFAULT);
        }

        ctxt = llog_get_context(obd, logcookies->lgc_subsys);
        if (ctxt == NULL)
                RETURN(-ENODEV);

        disk_obd = ctxt->loc_exp->exp_obd;
        push_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL);
        for (i = 0; i < num_cookies; i++, logcookies++) {
                cathandle = ctxt->loc_handle;
                LASSERT(cathandle != NULL);
                inode = cathandle->lgh_file->f_dentry->d_inode;

                handle = fsfilt_start_log(disk_obd, inode,
                                          FSFILT_OP_CANCEL_UNLINK, NULL, 1);
                if (IS_ERR(handle)) {
                        CERROR("fsfilt_start_log() failed: %ld\n",
                               PTR_ERR(handle));
                        GOTO(pop_ctxt, rc = PTR_ERR(handle));
                }

                rc = llog_cat_cancel_records(cathandle, 1, logcookies);

                /*
                 * Do not raise -ENOENT errors for resent rpcs. This rec already
                 * might be killed.
                 */
                if (rc == -ENOENT &&
                    (lustre_msg_get_flags(req->rq_reqmsg) & MSG_RESENT)) {
                        /*
                         * Do not change this message, reply-single.sh test_59b
                         * expects to find this in log.
                         */
                        CDEBUG(D_RPCTRACE, "RESENT cancel req %p - ignored\n",
                               req);
                        rc = 0;
                } else if (rc == 0) {
                        CDEBUG(D_RPCTRACE, "Canceled %d llog-records\n",
                               num_cookies);
                }

                err = fsfilt_commit(disk_obd, inode, handle, 0);
                if (err) {
                        CERROR("Error committing transaction: %d\n", err);
                        if (!rc)
                                rc = err;
                        failed++;
                        GOTO(pop_ctxt, rc);
                } else if (rc)
                        failed++;
        }
        GOTO(pop_ctxt, rc);
pop_ctxt:
        pop_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL);
        if (rc)
                CERROR("Cancel %d of %d llog-records failed: %d\n",
                       failed, num_cookies, rc);

        llog_ctxt_put(ctxt);
        return rc;
}
Beispiel #14
0
/*mds still need lov setup here*/
static int mds_cmd_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
{
        struct mds_obd *mds = &obd->u.mds;
        struct lvfs_run_ctxt saved;
        const char     *dev;
        struct vfsmount *mnt;
        struct lustre_sb_info *lsi;
        struct lustre_mount_info *lmi;
        struct dentry  *dentry;
        int rc = 0;
        ENTRY;

        CDEBUG(D_INFO, "obd %s setup \n", obd->obd_name);
        if (strncmp(obd->obd_name, MDD_OBD_NAME, strlen(MDD_OBD_NAME)))
                RETURN(0);

        if (lcfg->lcfg_bufcount < 5) {
                CERROR("invalid arg for setup %s\n", MDD_OBD_NAME);
                RETURN(-EINVAL);
        }
        dev = lustre_cfg_string(lcfg, 4);
        lmi = server_get_mount(dev);
        LASSERT(lmi != NULL);

        lsi = s2lsi(lmi->lmi_sb);
        mnt = lmi->lmi_mnt;
        /* FIXME: MDD LOV initialize objects.
         * we need only lmi here but not get mount
         * OSD did mount already, so put mount back
         */
        cfs_atomic_dec(&lsi->lsi_mounts);
        mntput(mnt);
        cfs_init_rwsem(&mds->mds_notify_lock);

        obd->obd_fsops = fsfilt_get_ops(MT_STR(lsi->lsi_ldd));
        mds_init_ctxt(obd, mnt);

        push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
        dentry = simple_mkdir(current->fs->pwd, mnt, "OBJECTS", 0777, 1);
        if (IS_ERR(dentry)) {
                rc = PTR_ERR(dentry);
                CERROR("cannot create OBJECTS directory: rc = %d\n", rc);
                GOTO(err_putfs, rc);
        }
        mds->mds_objects_dir = dentry;

        dentry = ll_lookup_one_len("__iopen__", current->fs->pwd,
                                strlen("__iopen__"));
        if (IS_ERR(dentry)) {
                rc = PTR_ERR(dentry);
                CERROR("cannot lookup __iopen__ directory: rc = %d\n", rc);
                GOTO(err_objects, rc);
        }

        mds->mds_fid_de = dentry;
        if (!dentry->d_inode || is_bad_inode(dentry->d_inode)) {
                rc = -ENOENT;
                CERROR("__iopen__ directory has no inode? rc = %d\n", rc);
                GOTO(err_fid, rc);
        }
        rc = mds_lov_init_objids(obd);
        if (rc != 0) {
               CERROR("cannot init lov objid rc = %d\n", rc);
               GOTO(err_fid, rc );
        }

        rc = mds_lov_presetup(mds, lcfg);
        if (rc < 0)
                GOTO(err_objects, rc);

        /* Don't wait for mds_postrecov trying to clear orphans */
        obd->obd_async_recov = 1;
        rc = mds_postsetup(obd);
        /* Bug 11557 - allow async abort_recov start
           FIXME can remove most of this obd_async_recov plumbing
        obd->obd_async_recov = 0;
        */

        if (rc)
                GOTO(err_objects, rc);

err_pop:
        pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
        RETURN(rc);
err_fid:
        dput(mds->mds_fid_de);
err_objects:
        dput(mds->mds_objects_dir);
err_putfs:
        fsfilt_put_ops(obd->obd_fsops);
        goto err_pop;
}
Beispiel #15
0
/* from mdt_iocontrol */
int mgs_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
                  void *karg, void *uarg)
{
        struct obd_device *obd = exp->exp_obd;
        struct obd_ioctl_data *data = karg;
        struct lvfs_run_ctxt saved;
        int rc = 0;

        ENTRY;
        CDEBUG(D_IOCTL, "handling ioctl cmd %#x\n", cmd);

        switch (cmd) {

        case OBD_IOC_PARAM: {
                struct lustre_cfg *lcfg;
                struct llog_rec_hdr rec;
                char fsname[MTI_NAME_MAXLEN];

                rec.lrh_len = llog_data_len(data->ioc_plen1);

                if (data->ioc_type == LUSTRE_CFG_TYPE) {
                        rec.lrh_type = OBD_CFG_REC;
                } else {
                        CERROR("unknown cfg record type:%d \n", data->ioc_type);
                        RETURN(-EINVAL);
                }

                OBD_ALLOC(lcfg, data->ioc_plen1);
                if (lcfg == NULL)
                        RETURN(-ENOMEM);
                if (cfs_copy_from_user(lcfg, data->ioc_pbuf1, data->ioc_plen1))
                        GOTO(out_free, rc = -EFAULT);

                if (lcfg->lcfg_bufcount < 1)
                        GOTO(out_free, rc = -EINVAL);

                rc = mgs_setparam(obd, lcfg, fsname);
                if (rc) {
                        CERROR("setparam err %d\n", rc);
                        GOTO(out_free, rc);
                }
out_free:
                OBD_FREE(lcfg, data->ioc_plen1);
                RETURN(rc);
        }

        case OBD_IOC_POOL: {
                RETURN(mgs_iocontrol_pool(obd, data));
        }

        case OBD_IOC_DUMP_LOG: {
                struct llog_ctxt *ctxt;
                ctxt = llog_get_context(obd, LLOG_CONFIG_ORIG_CTXT);
                push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
                rc = class_config_dump_llog(ctxt, data->ioc_inlbuf1, NULL);
                pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
                llog_ctxt_put(ctxt);

                RETURN(rc);
        }

        case OBD_IOC_LLOG_CHECK:
        case OBD_IOC_LLOG_INFO:
        case OBD_IOC_LLOG_PRINT: {
                struct llog_ctxt *ctxt;
                ctxt = llog_get_context(obd, LLOG_CONFIG_ORIG_CTXT);

                push_ctxt(&saved, &ctxt->loc_exp->exp_obd->obd_lvfs_ctxt, NULL);
                rc = llog_ioctl(ctxt, cmd, data);
                pop_ctxt(&saved, &ctxt->loc_exp->exp_obd->obd_lvfs_ctxt, NULL);
                llog_ctxt_put(ctxt);

                RETURN(rc);
        }

        default:
                CDEBUG(D_INFO, "unknown command %x\n", cmd);
                RETURN(-EINVAL);
        }
        RETURN(0);
}
Beispiel #16
0
static int llog_catinfo_deletions(struct obd_device *obd, char *buf,
                                  int buf_len)
{
        struct mds_obd *mds = &obd->u.mds;
        struct llog_handle *handle;
        struct lvfs_run_ctxt saved;
        int size, i, count;
        struct llog_catid *idarray;
        char name[32] = CATLIST;
        struct cb_data data;
        struct llog_ctxt *ctxt = llog_get_context(obd, LLOG_CONFIG_ORIG_CTXT);
        int rc;
        ENTRY;

        if (ctxt == NULL || mds == NULL)
                GOTO(release_ctxt, rc = -ENODEV);

        count = mds->mds_lov_desc.ld_tgt_count;
        size = sizeof(*idarray) * count;

        OBD_ALLOC_LARGE(idarray, size);
        if (!idarray)
                GOTO(release_ctxt, rc = -ENOMEM);

        cfs_mutex_lock(&obd->obd_olg.olg_cat_processing);
        rc = llog_get_cat_list(obd, name, 0, count, idarray);
        if (rc)
                GOTO(out_free, rc);

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

        data.ctxt = ctxt;
        data.out = buf;
        data.remains = buf_len;
        for (i = 0; i < count; i++) {
                int l, index, uncanceled = 0;

                rc = llog_create(ctxt, &handle, &idarray[i].lci_logid, NULL);
                if (rc)
                        GOTO(out_pop, rc);
                rc = llog_init_handle(handle, 0, NULL);
                if (rc) {
                        llog_close(handle);
                        GOTO(out_pop, rc = -ENOENT);
                }
                for (index = 1; index < (LLOG_BITMAP_BYTES * 8); index++) {
                        if (ext2_test_bit(index, handle->lgh_hdr->llh_bitmap))
                                uncanceled++;
                }
                l = snprintf(data.out, data.remains,
                             "\n[Catlog ID]: #"LPX64"#"LPX64"#%08x  "
                             "[Log Count]: %d\n",
                             idarray[i].lci_logid.lgl_oid,
                             idarray[i].lci_logid.lgl_oseq,
                             idarray[i].lci_logid.lgl_ogen, uncanceled);

                data.out += l;
                data.remains -= l;
                data.init = 1;

                llog_process(handle, llog_catinfo_cb, &data, NULL);
                llog_close(handle);

                if (data.remains <= 0)
                        break;
        }
        EXIT;
out_pop:
        pop_ctxt(&saved, &ctxt->loc_exp->exp_obd->obd_lvfs_ctxt, NULL);
out_free:
        cfs_mutex_unlock(&obd->obd_olg.olg_cat_processing);
        OBD_FREE_LARGE(idarray, size);
release_ctxt:
        llog_ctxt_put(ctxt);
        return rc;
}
Beispiel #17
0
int target_quota_check(struct obd_device *obd, struct obd_export *exp,
                       struct obd_quotactl *oqctl)
{
        struct obd_device_target *obt = &obd->u.obt;
        struct quotacheck_thread_args *qta;
        int rc = 0;
        ENTRY;

        OBD_ALLOC_PTR(qta);
        if (!qta)
                RETURN(ENOMEM);

        cfs_down(&obt->obt_quotachecking);

        qta->qta_exp = exp;
        qta->qta_obd = obd;
        qta->qta_oqctl = *oqctl;
        qta->qta_oqctl.qc_id = obt->obt_qfmt; /* override qfmt version */
        qta->qta_sb = obt->obt_sb;
        qta->qta_sem = &obt->obt_quotachecking;

        /* quotaoff firstly */
        oqctl->qc_cmd = Q_QUOTAOFF;
        if (!strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME)) {
                rc = do_mds_quota_off(obd, oqctl);
                if (rc && rc != -EALREADY) {
                        CERROR("off quota on MDS failed: %d\n", rc);
                        GOTO(out, rc);
                }

                /* quota master */
                rc = init_admin_quotafiles(obd, &qta->qta_oqctl);
                if (rc) {
                        CERROR("init_admin_quotafiles failed: %d\n", rc);
                        GOTO(out, rc);
                }
        } else {
                struct lvfs_run_ctxt saved;
                struct lustre_quota_ctxt *qctxt = &obt->obt_qctxt;

                push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
                rc = fsfilt_quotactl(obd, obt->obt_sb, oqctl);
                pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
                if (!rc) {
                        qctxt->lqc_flags &= ~UGQUOTA2LQC(oqctl->qc_type);
                } else if (!quota_is_off(qctxt, oqctl)) {
                        CERROR("off quota on OSS failed: %d\n", rc);
                        GOTO(out, rc);
                }
        }

        /* we get ref for exp because target_quotacheck_callback() will use this
         * export later b=18126 */
        class_export_get(exp);
        rc = cfs_kernel_thread(target_quotacheck_thread, qta,
                               CLONE_VM|CLONE_FILES);
        if (rc >= 0) {
                /* target_quotacheck_thread will drop the ref on exp and release
                 * obt_quotachecking */
                CDEBUG(D_INFO, "%s: target_quotacheck_thread: %d\n",
                       obd->obd_name, rc);
                RETURN(0);
        } else {
                CERROR("%s: error starting quotacheck_thread: %d\n",
                       obd->obd_name, rc);
                class_export_put(exp);
                EXIT;
        }

out:
        cfs_up(&obt->obt_quotachecking);
        OBD_FREE_PTR(qta);
        return rc;
}
Beispiel #18
0
static int llog_lvfs_destroy(struct llog_handle *handle)
{
        struct dentry *fdentry;
        struct obdo *oa;
        struct obd_device *obd = handle->lgh_ctxt->loc_exp->exp_obd;
        char *dir;
        void *th;
        struct inode *inode;
        int rc, rc1;
        ENTRY;

        dir = MOUNT_CONFIGS_DIR;

        fdentry = handle->lgh_file->f_dentry;
        inode = fdentry->d_parent->d_inode;
        if (strcmp(fdentry->d_parent->d_name.name, dir) == 0) {
                struct lvfs_run_ctxt saved;
                struct vfsmount *mnt = mntget(handle->lgh_file->f_vfsmnt);

                push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
                dget(fdentry);
                rc = llog_lvfs_close(handle);

                if (rc == 0) {
                        LOCK_INODE_MUTEX_PARENT(inode);
                        rc = ll_vfs_unlink(inode, fdentry, mnt);
                        UNLOCK_INODE_MUTEX(inode);
                }
                mntput(mnt);

                dput(fdentry);
                pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
                RETURN(rc);
        }

        OBDO_ALLOC(oa);
        if (oa == NULL)
                RETURN(-ENOMEM);

        oa->o_id = handle->lgh_id.lgl_oid;
        oa->o_seq = handle->lgh_id.lgl_oseq;
        oa->o_generation = handle->lgh_id.lgl_ogen;
#undef o_generation
        oa->o_valid = OBD_MD_FLID | OBD_MD_FLGROUP | OBD_MD_FLGENER;

        rc = llog_lvfs_close(handle);
        if (rc)
                GOTO(out, rc);

        th = fsfilt_start_log(obd, inode, FSFILT_OP_UNLINK, NULL, 1);
        if (IS_ERR(th)) {
                CERROR("fsfilt_start failed: %ld\n", PTR_ERR(th));
                GOTO(out, rc = PTR_ERR(th));
        }

        rc = obd_destroy(handle->lgh_ctxt->loc_exp, oa, NULL, NULL, NULL, NULL);

        rc1 = fsfilt_commit(obd, inode, th, 0);
        if (rc == 0 && rc1 != 0)
                rc = rc1;
 out:
        OBDO_FREE(oa);
        RETURN(rc);
}
Beispiel #19
0
int llog_origin_handle_prev_block(struct ptlrpc_request *req)
{
        struct obd_export    *exp = req->rq_export;
        struct obd_device    *obd = exp->exp_obd;
        struct llog_handle   *loghandle;
        struct llogd_body    *body;
        struct llogd_body    *repbody;
        struct obd_device    *disk_obd;
        struct lvfs_run_ctxt  saved;
        struct llog_ctxt     *ctxt;
        __u32                 flags;
        __u8                 *buf;
        void                 *ptr;
        int                   rc, rc2;
        ENTRY;

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

        OBD_ALLOC(buf, LLOG_CHUNK_SIZE);
        if (!buf)
                RETURN(-ENOMEM);

        ctxt = llog_get_context(obd, body->lgd_ctxt_idx);
        if (ctxt == NULL)
                GOTO(out_free, rc = -ENODEV);

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

        rc = llog_create(ctxt, &loghandle, &body->lgd_logid, NULL);
        if (rc)
                GOTO(out_pop, rc);

        flags = body->lgd_llh_flags;
        rc = llog_init_handle(loghandle, flags, NULL);
        if (rc)
                GOTO(out_close, rc);

        memset(buf, 0, LLOG_CHUNK_SIZE);
        rc = llog_prev_block(loghandle, body->lgd_index,
                             buf, LLOG_CHUNK_SIZE);
        if (rc)
                GOTO(out_close, rc);

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

        repbody = req_capsule_server_get(&req->rq_pill, &RMF_LLOGD_BODY);
        *repbody = *body;

        ptr = req_capsule_server_get(&req->rq_pill, &RMF_EADATA);
        memcpy(ptr, buf, LLOG_CHUNK_SIZE);
        GOTO(out_close, rc);
out_close:
        rc2 = llog_close(loghandle);
        if (!rc)
                rc = rc2;

out_pop:
        pop_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL);
        llog_ctxt_put(ctxt);
out_free:
        OBD_FREE(buf, LLOG_CHUNK_SIZE);
        return rc;
}
Beispiel #20
0
int filter_quota_ctl(struct obd_device *unused, struct obd_export *exp,
                     struct obd_quotactl *oqctl)
{
        struct obd_device *obd = exp->exp_obd;
        struct obd_device_target *obt = &obd->u.obt;
        struct lvfs_run_ctxt saved;
        struct lustre_quota_ctxt *qctxt = &obt->obt_qctxt;
        struct lustre_qunit_size *lqs;
        void *handle = NULL;
        struct timeval work_start;
        struct timeval work_end;
        long timediff;
        int rc = 0;
        ENTRY;

        cfs_gettimeofday(&work_start);
        switch (oqctl->qc_cmd) {
        case Q_QUOTAON:
                oqctl->qc_id = obt->obt_qfmt;
                rc = generic_quota_on(obd, oqctl, 0);
                break;
        case Q_FINVALIDATE:
        case Q_QUOTAOFF:
                cfs_down(&obt->obt_quotachecking);
                if (oqctl->qc_cmd == Q_FINVALIDATE &&
                    (obt->obt_qctxt.lqc_flags & UGQUOTA2LQC(oqctl->qc_type))) {
                        CWARN("quota[%u] is on yet\n", oqctl->qc_type);
                        cfs_up(&obt->obt_quotachecking);
                        rc = -EBUSY;
                        break;
                }
                oqctl->qc_id = obt->obt_qfmt; /* override qfmt version */
        case Q_GETOINFO:
        case Q_GETOQUOTA:
        case Q_GETQUOTA:
                /* In recovery scenario, this pending dqacq/dqrel might have
                 * been processed by master successfully before it's dquot
                 * on master enter recovery mode. We must wait for this
                 * dqacq/dqrel done then return the correct limits to master */
                if (oqctl->qc_stat == QUOTA_RECOVERING)
                        handle = quota_barrier(&obd->u.obt.obt_qctxt, oqctl, 1);

                push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
                rc = fsfilt_quotactl(obd, obt->obt_sb, oqctl);
                pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);

                if (oqctl->qc_stat == QUOTA_RECOVERING)
                        quota_unbarrier(handle);

                if (oqctl->qc_cmd == Q_QUOTAOFF ||
                    oqctl->qc_cmd == Q_FINVALIDATE) {
                        if (oqctl->qc_cmd == Q_QUOTAOFF) {
                                if (!rc)
                                        obt->obt_qctxt.lqc_flags &=
                                                ~UGQUOTA2LQC(oqctl->qc_type);
                                else if (quota_is_off(qctxt, oqctl))
                                                rc = -EALREADY;
                                CDEBUG(D_QUOTA, "%s: quotaoff type:flags:rc "
                                       "%u:%lu:%d\n", obd->obd_name,
                                       oqctl->qc_type, qctxt->lqc_flags, rc);
                        }
                        cfs_up(&obt->obt_quotachecking);
                }

                break;
        case Q_SETQUOTA:
                /* currently, it is only used for nullifying the quota */
                handle = quota_barrier(&obd->u.obt.obt_qctxt, oqctl, 1);

                push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
                rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl);

                if (!rc) {
                        oqctl->qc_cmd = Q_SYNC;
                        fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl);
                        oqctl->qc_cmd = Q_SETQUOTA;
                }
                pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
                quota_unbarrier(handle);

                lqs = quota_search_lqs(LQS_KEY(oqctl->qc_type, oqctl->qc_id),
                                       qctxt, 0);
                if (lqs == NULL || IS_ERR(lqs)){
                        CERROR("fail to create lqs during setquota operation "
                               "for %sid %u\n", oqctl->qc_type ? "g" : "u",
                               oqctl->qc_id);
                } else {
                        lqs->lqs_flags &= ~QB_SET;
                        lqs_putref(lqs);
                }

                break;
        case Q_INITQUOTA:
                {
                unsigned int id[MAXQUOTAS] = { 0, 0 };

                /* Initialize quota limit to MIN_QLIMIT */
                LASSERT(oqctl->qc_dqblk.dqb_valid == QIF_BLIMITS);
                LASSERT(oqctl->qc_dqblk.dqb_bsoftlimit == 0);

                if (!oqctl->qc_dqblk.dqb_bhardlimit)
                        goto adjust;

               /* There might be a pending dqacq/dqrel (which is going to
                 * clear stale limits on slave). we should wait for it's
                 * completion then initialize limits */
                handle = quota_barrier(&obd->u.obt.obt_qctxt, oqctl, 1);
                LASSERT(oqctl->qc_dqblk.dqb_bhardlimit == MIN_QLIMIT);
                push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
                rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl);

                /* Update on-disk quota, in case of lose the changed limits
                 * (MIN_QLIMIT) on crash, which cannot be recovered.*/
                if (!rc) {
                        oqctl->qc_cmd = Q_SYNC;
                        fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl);
                        oqctl->qc_cmd = Q_INITQUOTA;
                }
                pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
                quota_unbarrier(handle);

                if (rc)
                        RETURN(rc);
adjust:
                lqs = quota_search_lqs(LQS_KEY(oqctl->qc_type, oqctl->qc_id),
                                       qctxt, 1);
                if (lqs == NULL || IS_ERR(lqs)){
                        CERROR("fail to create lqs during setquota operation "
                               "for %sid %u\n", oqctl->qc_type ? "g" : "u",
                               oqctl->qc_id);
                        break;
                } else {
                        lqs->lqs_flags |= QB_SET;
                        lqs_putref(lqs);
                }

                /* Trigger qunit pre-acquire */
                if (oqctl->qc_type == USRQUOTA)
                        id[USRQUOTA] = oqctl->qc_id;
                else
                        id[GRPQUOTA] = oqctl->qc_id;

                rc = qctxt_adjust_qunit(obd, &obd->u.obt.obt_qctxt,
                                        id, 1, 0, NULL);
                if (rc == -EDQUOT || rc == -EBUSY) {
                        CDEBUG(D_QUOTA, "rc: %d.\n", rc);
                        rc = 0;
                }

                break;
                }
        default:
                CERROR("%s: unsupported filter_quotactl command: %d\n",
                       obd->obd_name, oqctl->qc_cmd);
                RETURN(-EFAULT);
        }
        cfs_gettimeofday(&work_end);
        timediff = cfs_timeval_sub(&work_end, &work_start, NULL);
        lprocfs_counter_add(qctxt->lqc_stats, LQUOTA_QUOTA_CTL, timediff);

        RETURN(rc);
}
Beispiel #21
0
static int llog_lvfs_destroy(const struct lu_env *env,
			     struct llog_handle *handle)
{
	struct dentry *fdentry;
	struct obdo *oa;
	struct obd_device *obd = handle->lgh_ctxt->loc_exp->exp_obd;
	char *dir;
	void *th;
	struct inode *inode;
	int rc, rc1;

	dir = MOUNT_CONFIGS_DIR;

	LASSERT(handle->lgh_file);
	fdentry = handle->lgh_file->f_dentry;
	inode = fdentry->d_parent->d_inode;
	if (strcmp(fdentry->d_parent->d_name.name, dir) == 0) {
		struct lvfs_run_ctxt saved;
		struct vfsmount *mnt = mntget(handle->lgh_file->f_vfsmnt);

		push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
		dget(fdentry);
		rc = llog_lvfs_close(env, handle);
		if (rc == 0) {
			mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT);
			rc = ll_vfs_unlink(inode, fdentry, mnt);
			mutex_unlock(&inode->i_mutex);
		}
		mntput(mnt);

		dput(fdentry);
		pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
		return rc;
	}

	OBDO_ALLOC(oa);
	if (oa == NULL)
		return -ENOMEM;

	oa->o_oi = handle->lgh_id.lgl_oi;
	oa->o_generation = handle->lgh_id.lgl_ogen;
#undef o_generation
	oa->o_valid = OBD_MD_FLID | OBD_MD_FLGROUP | OBD_MD_FLGENER;

	rc = llog_lvfs_close(env, handle);
	if (rc)
		GOTO(out, rc);

	th = fsfilt_start_log(obd, inode, FSFILT_OP_UNLINK, NULL, 1);
	if (IS_ERR(th)) {
		CERROR("fsfilt_start failed: %ld\n", PTR_ERR(th));
		GOTO(out, rc = PTR_ERR(th));
	}

	rc = obd_destroy(NULL, handle->lgh_ctxt->loc_exp, oa,
			 NULL, NULL, NULL, NULL);

	rc1 = fsfilt_commit(obd, inode, th, 0);
	if (rc == 0 && rc1 != 0)
		rc = rc1;
 out:
	OBDO_FREE(oa);
	return rc;
}