Exemplo n.º 1
0
int
lst_group_del_ioctl(lstio_group_del_args_t *args)
{
        int     rc;
        char   *name;

        if (args->lstio_grp_key != console_session.ses_key)
                return -EACCES;

        if (args->lstio_grp_namep == NULL ||
            args->lstio_grp_nmlen <= 0 ||
            args->lstio_grp_nmlen > LST_NAME_SIZE)
                return -EINVAL;

        LIBCFS_ALLOC(name, args->lstio_grp_nmlen + 1);
        if (name == NULL)
                return -ENOMEM;

        if (cfs_copy_from_user(name,
                               args->lstio_grp_namep,
                               args->lstio_grp_nmlen)) {
                LIBCFS_FREE(name, args->lstio_grp_nmlen + 1);
                return -EFAULT;
        }

        name[args->lstio_grp_nmlen] = 0;

        rc = lstcon_group_del(name);

        LIBCFS_FREE(name, args->lstio_grp_nmlen + 1);

        return rc;
}
Exemplo n.º 2
0
static int osc_wd_checksum_type(struct file *file, const char *buffer,
                                unsigned long count, void *data)
{
        struct obd_device *obd = data;
        int i;
        DECLARE_CKSUM_NAME;
        char kernbuf[10];

        if (obd == NULL)
                return 0;

        if (count > sizeof(kernbuf) - 1)
                return -EINVAL;
        if (cfs_copy_from_user(kernbuf, buffer, count))
                return -EFAULT;
        if (count > 0 && kernbuf[count - 1] == '\n')
                kernbuf[count - 1] = '\0';
        else
                kernbuf[count] = '\0';

        for (i = 0; i < ARRAY_SIZE(cksum_name); i++) {
                if (((1 << i) & obd->u.cli.cl_supp_cksum_types) == 0)
                        continue;
                if (!strcmp(kernbuf, cksum_name[i])) {
                       obd->u.cli.cl_cksum_type = 1 << i;
                       return count;
                }
        }
        return -EINVAL;
}
Exemplo n.º 3
0
static int lprocfs_wr_changelog_mask(struct file *file, const char *buffer,
                                     unsigned long count, void *data)
{
        struct mdd_device *mdd = data;
        char *kernbuf;
        int rc;
        ENTRY;

        if (count >= CFS_PAGE_SIZE)
                RETURN(-EINVAL);
        OBD_ALLOC(kernbuf, CFS_PAGE_SIZE);
        if (kernbuf == NULL)
                RETURN(-ENOMEM);
        if (cfs_copy_from_user(kernbuf, buffer, count))
                GOTO(out, rc = -EFAULT);
        kernbuf[count] = 0;

        rc = cfs_str2mask(kernbuf, changelog_type2str, &mdd->mdd_cl.mc_mask,
                          CHANGELOG_MINMASK, CHANGELOG_ALLMASK);
        if (rc == 0)
                rc = count;
out:
        OBD_FREE(kernbuf, CFS_PAGE_SIZE);
        return rc;
}
Exemplo n.º 4
0
int
lst_batch_stop_ioctl(lstio_batch_stop_args_t *args)
{
        int             rc;
        char           *name;

        if (args->lstio_bat_key != console_session.ses_key)
                return -EACCES;

        if (args->lstio_bat_resultp == NULL ||
            args->lstio_bat_namep == NULL ||
            args->lstio_bat_nmlen <= 0 ||
            args->lstio_bat_nmlen > LST_NAME_SIZE)
                return -EINVAL;

        LIBCFS_ALLOC(name, args->lstio_bat_nmlen + 1);
        if (name == NULL)
                return -ENOMEM;

        if (cfs_copy_from_user(name,
                               args->lstio_bat_namep,
                               args->lstio_bat_nmlen)) {
                LIBCFS_FREE(name, args->lstio_bat_nmlen + 1);
                return -EFAULT;
        }

        name[args->lstio_bat_nmlen] = 0;

        rc = lstcon_batch_stop(name, args->lstio_bat_force,
                               args->lstio_bat_resultp);

        LIBCFS_FREE(name, args->lstio_bat_nmlen + 1);

        return rc;
}
Exemplo n.º 5
0
int
lst_group_update_ioctl(lstio_group_update_args_t *args)
{
        int     rc;
        char   *name;

        if (args->lstio_grp_key != console_session.ses_key)
                return -EACCES;

        if (args->lstio_grp_resultp == NULL ||
            args->lstio_grp_namep == NULL ||
            args->lstio_grp_nmlen <= 0 || 
            args->lstio_grp_nmlen > LST_NAME_SIZE)
                return -EINVAL;

        LIBCFS_ALLOC(name, args->lstio_grp_nmlen + 1);
        if (name == NULL)
                return -ENOMEM;

        if (cfs_copy_from_user(name,
                           args->lstio_grp_namep,
                           args->lstio_grp_nmlen)) {
                LIBCFS_FREE(name, args->lstio_grp_nmlen + 1);
                return -EFAULT;
        }

        name[args->lstio_grp_nmlen] = 0;

        switch (args->lstio_grp_opc) {
        case LST_GROUP_CLEAN:
                rc = lstcon_group_clean(name, args->lstio_grp_args);
                break;

        case LST_GROUP_REFRESH:
                rc = lstcon_group_refresh(name, args->lstio_grp_resultp);
                break;

        case LST_GROUP_RMND:
                if (args->lstio_grp_count  <= 0 ||
                    args->lstio_grp_idsp == NULL) {
                        rc = -EINVAL;
                        break;
                }
                rc = lstcon_nodes_remove(name, args->lstio_grp_count,
                                         args->lstio_grp_idsp,
                                         args->lstio_grp_resultp);
                break;

        default:
                rc = -EINVAL;
                break;
        }

        LIBCFS_FREE(name, args->lstio_grp_nmlen + 1);

        return rc;
}
Exemplo n.º 6
0
int lprocfs_quota_wr_type(struct file *file, const char *buffer,
                          unsigned long count, void *data)
{
        struct obd_device *obd = (struct obd_device *)data;
        struct obd_device_target *obt;
        int type = 0, is_mds;
        unsigned long i;
        char stype[MAX_STYPE_SIZE + 1] = "";

        LASSERT(obd != NULL);

        obt = &obd->u.obt;

        is_mds = !strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME);

        if (count > MAX_STYPE_SIZE)
                return -EINVAL;

        if (cfs_copy_from_user(stype, buffer, count))
                return -EFAULT;

        for (i = 0 ; i < count ; i++) {
                switch (stype[i]) {
                case 'u' :
                        type |= USER_QUOTA;
                        break;
                case 'g' :
                        type |= GROUP_QUOTA;
                        break;
                case '1' :
                case '2' :
                        CWARN("quota_type options 1 and 2 are obsolete, "
                              "they will be ignored\n");
                        break;
                case '3' : /* the only valid version spec, do nothing */
                default  : /* just skip stray symbols like \n */
                        break;
                }
        }

        if (type != 0) {
                int rc = auto_quota_on(obd, type - 1);

                if (rc && rc != -EALREADY && rc != -ENOENT)
                        return rc;
        }

        return count;
}
Exemplo n.º 7
0
int
lst_stat_query_ioctl(lstio_stat_args_t *args)
{
        int             rc;
        char           *name;

        /* TODO: not finished */
        if (args->lstio_sta_key != console_session.ses_key)
                return -EACCES;

        if (args->lstio_sta_resultp == NULL ||
            (args->lstio_sta_namep  == NULL &&
             args->lstio_sta_idsp   == NULL) ||
            args->lstio_sta_nmlen <= 0 ||
            args->lstio_sta_nmlen > LST_NAME_SIZE)
                return -EINVAL;

        if (args->lstio_sta_idsp != NULL &&
            args->lstio_sta_count <= 0)
                return -EINVAL;

        LIBCFS_ALLOC(name, args->lstio_sta_nmlen + 1);
        if (name == NULL)
                return -ENOMEM;

        if (cfs_copy_from_user(name, args->lstio_sta_namep,
                               args->lstio_sta_nmlen)) {
                LIBCFS_FREE(name, args->lstio_sta_nmlen + 1);
                return -EFAULT;
        }

        if (args->lstio_sta_idsp == NULL) {
                rc = lstcon_group_stat(name, args->lstio_sta_timeout,
                                       args->lstio_sta_resultp);
        } else {
                rc = lstcon_nodes_stat(args->lstio_sta_count,
                                       args->lstio_sta_idsp,
                                       args->lstio_sta_timeout,
                                       args->lstio_sta_resultp);
        }

        LIBCFS_FREE(name, args->lstio_sta_nmlen + 1);

        return rc;
}
Exemplo n.º 8
0
int
lst_batch_query_ioctl(lstio_batch_query_args_t *args)
{
        char   *name;
        int     rc;

        if (args->lstio_bat_key != console_session.ses_key)
                return -EACCES;

        if (args->lstio_bat_resultp == NULL ||
            args->lstio_bat_namep == NULL ||
            args->lstio_bat_nmlen <= 0 ||
            args->lstio_bat_nmlen > LST_NAME_SIZE)
                return -EINVAL;

        if (args->lstio_bat_testidx < 0)
                return -EINVAL;

        LIBCFS_ALLOC(name, args->lstio_bat_nmlen + 1);
        if (name == NULL)
                return -ENOMEM;

        if (cfs_copy_from_user(name,
                               args->lstio_bat_namep,
                               args->lstio_bat_nmlen)) {
                LIBCFS_FREE(name, args->lstio_bat_nmlen + 1);
                return -EFAULT;
        }

        name[args->lstio_bat_nmlen] = 0;

        rc = lstcon_test_batch_query(name,
                                     args->lstio_bat_testidx,
                                     args->lstio_bat_client,
                                     args->lstio_bat_timeout,
                                     args->lstio_bat_resultp);

        LIBCFS_FREE(name, args->lstio_bat_nmlen + 1);

        return rc;
}
Exemplo n.º 9
0
static int lprocfs_wr_atime_diff(struct file *file, const char *buffer,
                                 unsigned long count, void *data)
{
        struct mdd_device *mdd = data;
        char kernbuf[20], *end;
        unsigned long diff = 0;

        if (count > (sizeof(kernbuf) - 1))
                return -EINVAL;

        if (cfs_copy_from_user(kernbuf, buffer, count))
                return -EFAULT;

        kernbuf[count] = '\0';

        diff = simple_strtoul(kernbuf, &end, 0);
        if (kernbuf == end)
                return -EINVAL;

        mdd->mdd_atime_diff = diff;
        return count;
}
Exemplo n.º 10
0
int
lst_nodes_add_ioctl(lstio_group_nodes_args_t *args)
{
        int     rc;
        char   *name;

        if (args->lstio_grp_key != console_session.ses_key)
                return -EACCES;

        if (args->lstio_grp_idsp == NULL || /* array of ids */
            args->lstio_grp_count <= 0 ||
            args->lstio_grp_resultp == NULL ||
            args->lstio_grp_namep == NULL ||
            args->lstio_grp_nmlen <= 0 || 
            args->lstio_grp_nmlen > LST_NAME_SIZE)
                return -EINVAL;

        LIBCFS_ALLOC(name, args->lstio_grp_nmlen + 1);
        if (name == NULL)
                return -ENOMEM;

        if (cfs_copy_from_user(name, args->lstio_grp_namep,
                               args->lstio_grp_nmlen)) {
                LIBCFS_FREE(name, args->lstio_grp_nmlen + 1);

                return -EFAULT;
        }

        name[args->lstio_grp_nmlen] = 0;

        rc = lstcon_nodes_add(name, args->lstio_grp_count,
                              args->lstio_grp_idsp,
                              args->lstio_grp_resultp);

        LIBCFS_FREE(name, args->lstio_grp_nmlen + 1);

        return rc;
}
Exemplo n.º 11
0
int
lst_session_new_ioctl(lstio_session_new_args_t *args)
{
        char      *name;
        int        rc;

        if (args->lstio_ses_idp   == NULL || /* address for output sid */
            args->lstio_ses_key   == 0 || /* no key is specified */
            args->lstio_ses_namep == NULL || /* session name */
            args->lstio_ses_nmlen <= 0 ||
            args->lstio_ses_nmlen > LST_NAME_SIZE)
                return -EINVAL;

        LIBCFS_ALLOC(name, args->lstio_ses_nmlen + 1);
        if (name == NULL)
                return -ENOMEM;

        if (cfs_copy_from_user(name,
                               args->lstio_ses_namep,
                               args->lstio_ses_nmlen)) {
                LIBCFS_FREE(name, args->lstio_ses_nmlen + 1);
                return -EFAULT;
        }

        name[args->lstio_ses_nmlen] = 0;

        rc = lstcon_session_new(name,
                             args->lstio_ses_key,
                             args->lstio_ses_timeout,
                             args->lstio_ses_force,
                             args->lstio_ses_idp);

        LIBCFS_FREE(name, args->lstio_ses_nmlen + 1);

        return rc;
}
Exemplo n.º 12
0
int
lst_batch_info_ioctl(lstio_batch_info_args_t *args)
{
        char           *name;
        int             rc;
        int             index;
        int             ndent;

        if (args->lstio_bat_key != console_session.ses_key)
                return -EACCES;

        if (args->lstio_bat_namep == NULL || /* batch name */
            args->lstio_bat_nmlen <= 0 ||
            args->lstio_bat_nmlen > LST_NAME_SIZE)
                return -EINVAL;

        if (args->lstio_bat_entp == NULL && /* output: batch entry */
            args->lstio_bat_dentsp == NULL) /* output: node entry */
                return -EINVAL;

        if (args->lstio_bat_dentsp != NULL) { /* have node entry */
                if (args->lstio_bat_idxp == NULL || /* node index */
                    args->lstio_bat_ndentp == NULL) /* # of node entry */
                        return -EINVAL;

                if (cfs_copy_from_user(&index, args->lstio_bat_idxp,
                                       sizeof(index)) ||
                    cfs_copy_from_user(&ndent, args->lstio_bat_ndentp,
                                       sizeof(ndent)))
                        return -EFAULT;

                if (ndent <= 0 || index < 0)
                        return -EINVAL;
        }

        LIBCFS_ALLOC(name, args->lstio_bat_nmlen + 1);
        if (name == NULL)
                return -ENOMEM;

        if (cfs_copy_from_user(name,
                               args->lstio_bat_namep, args->lstio_bat_nmlen)) {
                LIBCFS_FREE(name, args->lstio_bat_nmlen + 1);
                return -EFAULT;
        }

        name[args->lstio_bat_nmlen] = 0;

        rc = lstcon_batch_info(name,
                            args->lstio_bat_entp, args->lstio_bat_server,
                            args->lstio_bat_testidx, &index, &ndent,
                            args->lstio_bat_dentsp);

        LIBCFS_FREE(name, args->lstio_bat_nmlen + 1);

        if (rc != 0)
                return rc;

        if (args->lstio_bat_dentsp != NULL && 
            (cfs_copy_to_user(args->lstio_bat_idxp, &index, sizeof(index)) ||
             cfs_copy_to_user(args->lstio_bat_ndentp, &ndent, sizeof(ndent))))
                rc = -EFAULT;

        return rc;
}
Exemplo n.º 13
0
static int mgs_iocontrol_pool(struct obd_device *obd,
                              struct obd_ioctl_data *data)
{
        int rc;
        struct lustre_cfg *lcfg = NULL;
        struct llog_rec_hdr rec;
        char *fsname = NULL;
        char *poolname = NULL;
        ENTRY;

        OBD_ALLOC(fsname, MTI_NAME_MAXLEN);
        if (fsname == NULL)
                RETURN(-ENOMEM);

        OBD_ALLOC(poolname, LOV_MAXPOOLNAME + 1);
        if (poolname == NULL) {
                rc = -ENOMEM;
                GOTO(out_pool, rc);
        }
        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);
                rc = -EINVAL;
                GOTO(out_pool, rc);
        }

        if (data->ioc_plen1 > CFS_PAGE_SIZE) {
                rc = -E2BIG;
                GOTO(out_pool, rc);
        }

        OBD_ALLOC(lcfg, data->ioc_plen1);
        if (lcfg == NULL)
                GOTO(out_pool, rc = -ENOMEM);

        if (cfs_copy_from_user(lcfg, data->ioc_pbuf1, data->ioc_plen1))
                GOTO(out_pool, rc = -EFAULT);

        if (lcfg->lcfg_bufcount < 2) {
                GOTO(out_pool, rc = -EFAULT);
        }

        /* first arg is always <fsname>.<poolname> */
        mgs_extract_fs_pool(lustre_cfg_string(lcfg, 1), fsname,
                            poolname);

        switch (lcfg->lcfg_command) {
        case LCFG_POOL_NEW: {
                if (lcfg->lcfg_bufcount != 2)
                        RETURN(-EINVAL);
                rc = mgs_pool_cmd(obd, LCFG_POOL_NEW, fsname,
                                  poolname, NULL);
                break;
        }
        case LCFG_POOL_ADD: {
                if (lcfg->lcfg_bufcount != 3)
                        RETURN(-EINVAL);
                rc = mgs_pool_cmd(obd, LCFG_POOL_ADD, fsname, poolname,
                                  lustre_cfg_string(lcfg, 2));
                break;
        }
        case LCFG_POOL_REM: {
                if (lcfg->lcfg_bufcount != 3)
                        RETURN(-EINVAL);
                rc = mgs_pool_cmd(obd, LCFG_POOL_REM, fsname, poolname,
                                  lustre_cfg_string(lcfg, 2));
                break;
        }
        case LCFG_POOL_DEL: {
                if (lcfg->lcfg_bufcount != 2)
                        RETURN(-EINVAL);
                rc = mgs_pool_cmd(obd, LCFG_POOL_DEL, fsname,
                                  poolname, NULL);
                break;
        }
        default: {
                 rc = -EINVAL;
                 GOTO(out_pool, rc);
        }
        }

        if (rc) {
                CERROR("OBD_IOC_POOL err %d, cmd %X for pool %s.%s\n",
                       rc, lcfg->lcfg_command, fsname, poolname);
                GOTO(out_pool, rc);
        }

out_pool:
        if (lcfg != NULL)
                OBD_FREE(lcfg, data->ioc_plen1);

        if (fsname != NULL)
                OBD_FREE(fsname, MTI_NAME_MAXLEN);

        if (poolname != NULL)
                OBD_FREE(poolname, LOV_MAXPOOLNAME + 1);

        RETURN(rc);
}
Exemplo n.º 14
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);
}
Exemplo n.º 15
0
static int lprocfs_wr_lru_size(struct file *file, const char *buffer,
                               unsigned long count, void *data)
{
        struct ldlm_namespace *ns = data;
        char dummy[MAX_STRING_SIZE + 1], *end;
        unsigned long tmp;
        int lru_resize;

        dummy[MAX_STRING_SIZE] = '\0';
        if (cfs_copy_from_user(dummy, buffer, MAX_STRING_SIZE))
                return -EFAULT;

        if (strncmp(dummy, "clear", 5) == 0) {
                CDEBUG(D_DLMTRACE,
                       "dropping all unused locks from namespace %s\n",
                       ldlm_ns_name(ns));
                if (ns_connect_lru_resize(ns)) {
                        int canceled, unused  = ns->ns_nr_unused;

                        /* Try to cancel all @ns_nr_unused locks. */
                        canceled = ldlm_cancel_lru(ns, unused, LDLM_SYNC,
                                                   LDLM_CANCEL_PASSED);
                        if (canceled < unused) {
                                CDEBUG(D_DLMTRACE,
                                       "not all requested locks are canceled, "
                                       "requested: %d, canceled: %d\n", unused,
                                       canceled);
                                return -EINVAL;
                        }
                } else {
                        tmp = ns->ns_max_unused;
                        ns->ns_max_unused = 0;
                        ldlm_cancel_lru(ns, 0, LDLM_SYNC, LDLM_CANCEL_PASSED);
                        ns->ns_max_unused = tmp;
                }
                return count;
        }

        tmp = simple_strtoul(dummy, &end, 0);
        if (dummy == end) {
                CERROR("invalid value written\n");
                return -EINVAL;
        }
        lru_resize = (tmp == 0);

        if (ns_connect_lru_resize(ns)) {
                if (!lru_resize)
                        ns->ns_max_unused = (unsigned int)tmp;

                if (tmp > ns->ns_nr_unused)
                        tmp = ns->ns_nr_unused;
                tmp = ns->ns_nr_unused - tmp;

                CDEBUG(D_DLMTRACE,
                       "changing namespace %s unused locks from %u to %u\n",
                       ldlm_ns_name(ns), ns->ns_nr_unused,
                       (unsigned int)tmp);
                ldlm_cancel_lru(ns, tmp, LDLM_ASYNC, LDLM_CANCEL_PASSED);

                if (!lru_resize) {
                        CDEBUG(D_DLMTRACE,
                               "disable lru_resize for namespace %s\n",
                               ldlm_ns_name(ns));
                        ns->ns_connect_flags &= ~OBD_CONNECT_LRU_RESIZE;
                }
        } else {
                CDEBUG(D_DLMTRACE,
                       "changing namespace %s max_unused from %u to %u\n",
                       ldlm_ns_name(ns), ns->ns_max_unused,
                       (unsigned int)tmp);
                ns->ns_max_unused = (unsigned int)tmp;
                ldlm_cancel_lru(ns, 0, LDLM_ASYNC, LDLM_CANCEL_PASSED);

		/* Make sure that LRU resize was originally supported before
		 * turning it on here. */
                if (lru_resize &&
                    (ns->ns_orig_connect_flags & OBD_CONNECT_LRU_RESIZE)) {
                        CDEBUG(D_DLMTRACE,
                               "enable lru_resize for namespace %s\n",
                               ldlm_ns_name(ns));
                        ns->ns_connect_flags |= OBD_CONNECT_LRU_RESIZE;
                }
        }

        return count;
}
Exemplo n.º 16
0
int
lstcon_ioctl_entry(unsigned int cmd, struct libcfs_ioctl_data *data)
{
        char   *buf;
        int     opc = data->ioc_u32[0];
        int     rc;

        if (cmd != IOC_LIBCFS_LNETST)
                return -EINVAL;

        if (data->ioc_plen1 > CFS_PAGE_SIZE)
                return -EINVAL;

        LIBCFS_ALLOC(buf, data->ioc_plen1);
        if (buf == NULL)
                return -ENOMEM;

        /* copy in parameter */
        if (cfs_copy_from_user(buf, data->ioc_pbuf1, data->ioc_plen1)) {
                LIBCFS_FREE(buf, data->ioc_plen1);
                return -EFAULT;
        }

        cfs_mutex_down(&console_session.ses_mutex);

        console_session.ses_laststamp = cfs_time_current_sec();

        if (console_session.ses_shutdown) {
                rc = -ESHUTDOWN;
                goto out;
        }

        if (console_session.ses_expired)
                lstcon_session_end();

        if (opc != LSTIO_SESSION_NEW &&
            console_session.ses_state == LST_SESSION_NONE) {
                CDEBUG(D_NET, "LST no active session\n");
                rc = -ESRCH;
                goto out;
        }

        memset(&console_session.ses_trans_stat, 0, sizeof(lstcon_trans_stat_t));

        switch (opc) {
                case LSTIO_SESSION_NEW:
                        rc = lst_session_new_ioctl((lstio_session_new_args_t *)buf);
                        break;
                case LSTIO_SESSION_END:
                        rc = lst_session_end_ioctl((lstio_session_end_args_t *)buf);
                        break;
                case LSTIO_SESSION_INFO:
                        rc = lst_session_info_ioctl((lstio_session_info_args_t *)buf);
                        break;
                case LSTIO_DEBUG:
                        rc = lst_debug_ioctl((lstio_debug_args_t *)buf);
                        break;
                case LSTIO_GROUP_ADD:
                        rc = lst_group_add_ioctl((lstio_group_add_args_t *)buf);
                        break;
                case LSTIO_GROUP_DEL:
                        rc = lst_group_del_ioctl((lstio_group_del_args_t *)buf);
                        break;
                case LSTIO_GROUP_UPDATE:
                        rc = lst_group_update_ioctl((lstio_group_update_args_t *)buf);
                        break;
                case LSTIO_NODES_ADD:
                        rc = lst_nodes_add_ioctl((lstio_group_nodes_args_t *)buf);
                        break;
                case LSTIO_GROUP_LIST:
                        rc = lst_group_list_ioctl((lstio_group_list_args_t *)buf);
                        break;
                case LSTIO_GROUP_INFO:
                        rc = lst_group_info_ioctl((lstio_group_info_args_t *)buf);
                        break;
                case LSTIO_BATCH_ADD:
                        rc = lst_batch_add_ioctl((lstio_batch_add_args_t *)buf);
                        break;
                case LSTIO_BATCH_START:
                        rc = lst_batch_run_ioctl((lstio_batch_run_args_t *)buf);
                        break;
                case LSTIO_BATCH_STOP:
                        rc = lst_batch_stop_ioctl((lstio_batch_stop_args_t *)buf);
                        break;
                case LSTIO_BATCH_QUERY:
                        rc = lst_batch_query_ioctl((lstio_batch_query_args_t *)buf);
                        break;
                case LSTIO_BATCH_LIST:
                        rc = lst_batch_list_ioctl((lstio_batch_list_args_t *)buf);
                        break;
                case LSTIO_BATCH_INFO:
                        rc = lst_batch_info_ioctl((lstio_batch_info_args_t *)buf);
                        break;
                case LSTIO_TEST_ADD:
                        rc = lst_test_add_ioctl((lstio_test_args_t *)buf);
                        break;
                case LSTIO_STAT_QUERY:
                        rc = lst_stat_query_ioctl((lstio_stat_args_t *)buf);
                        break;
                default:
                        rc = -EINVAL;
        }

        if (cfs_copy_to_user(data->ioc_pbuf2, &console_session.ses_trans_stat,
                             sizeof(lstcon_trans_stat_t)))
                rc = -EFAULT;
out:
        cfs_mutex_up(&console_session.ses_mutex);

        LIBCFS_FREE(buf, data->ioc_plen1);

        return rc;
}
Exemplo n.º 17
0
int lst_test_add_ioctl(lstio_test_args_t *args)
{
        char           *name;
        char           *srcgrp = NULL;
        char           *dstgrp = NULL;
        void           *param = NULL;
        int             ret = 0;
        int             rc = -ENOMEM;

        if (args->lstio_tes_resultp == NULL ||
            args->lstio_tes_retp == NULL ||
            args->lstio_tes_bat_name == NULL || /* no specified batch */
            args->lstio_tes_bat_nmlen <= 0 ||
            args->lstio_tes_bat_nmlen > LST_NAME_SIZE ||
            args->lstio_tes_sgrp_name == NULL || /* no source group */
            args->lstio_tes_sgrp_nmlen <= 0 ||
            args->lstio_tes_sgrp_nmlen > LST_NAME_SIZE ||
            args->lstio_tes_dgrp_name == NULL || /* no target group */
            args->lstio_tes_dgrp_nmlen <= 0 ||
            args->lstio_tes_dgrp_nmlen > LST_NAME_SIZE)
                return -EINVAL;

        /* have parameter, check if parameter length is valid */
        if (args->lstio_tes_param != NULL &&
            (args->lstio_tes_param_len <= 0 ||
             args->lstio_tes_param_len > CFS_PAGE_SIZE - sizeof(lstcon_test_t)))
                return -EINVAL;

        LIBCFS_ALLOC(name, args->lstio_tes_bat_nmlen + 1);
        if (name == NULL)
                return rc;

        LIBCFS_ALLOC(srcgrp, args->lstio_tes_sgrp_nmlen + 1);
        if (srcgrp == NULL) 
                goto out;

        LIBCFS_ALLOC(dstgrp, args->lstio_tes_dgrp_nmlen + 1);
        if (srcgrp == NULL) 
                goto out;

        if (args->lstio_tes_param != NULL) {
                LIBCFS_ALLOC(param, args->lstio_tes_param_len);
                if (param == NULL) 
                        goto out;
        }

        rc = -EFAULT;
        if (cfs_copy_from_user(name,
                              args->lstio_tes_bat_name,
                              args->lstio_tes_bat_nmlen) ||
            cfs_copy_from_user(srcgrp,
                              args->lstio_tes_sgrp_name,
                              args->lstio_tes_sgrp_nmlen) ||
            cfs_copy_from_user(dstgrp,
                              args->lstio_tes_dgrp_name,
                              args->lstio_tes_dgrp_nmlen) ||
            cfs_copy_from_user(param, args->lstio_tes_param,
                              args->lstio_tes_param_len))
                goto out;

        rc = lstcon_test_add(name,
                            args->lstio_tes_type,
                            args->lstio_tes_loop,
                            args->lstio_tes_concur,
                            args->lstio_tes_dist, args->lstio_tes_span,
                            srcgrp, dstgrp, param, args->lstio_tes_param_len,
                            &ret, args->lstio_tes_resultp);

        if (ret != 0)
                rc = (cfs_copy_to_user(args->lstio_tes_retp, &ret,
                                       sizeof(ret))) ? -EFAULT : 0;
out:
        if (name != NULL)
                LIBCFS_FREE(name, args->lstio_tes_bat_nmlen + 1);

        if (srcgrp != NULL)
                LIBCFS_FREE(srcgrp, args->lstio_tes_sgrp_nmlen + 1);

        if (dstgrp != NULL)
                LIBCFS_FREE(dstgrp, args->lstio_tes_dgrp_nmlen + 1);

        if (param != NULL)
                LIBCFS_FREE(param, args->lstio_tes_param_len);

        return rc;
}
Exemplo n.º 18
0
int
lst_debug_ioctl(lstio_debug_args_t *args)
{
        char   *name   = NULL;
        int     client = 1;
        int     rc;

        if (args->lstio_dbg_key != console_session.ses_key)
                return -EACCES;

        if (args->lstio_dbg_resultp == NULL)
                return -EINVAL;

        if (args->lstio_dbg_namep != NULL && /* name of batch/group */
            (args->lstio_dbg_nmlen <= 0 ||
             args->lstio_dbg_nmlen > LST_NAME_SIZE))
                return -EINVAL;

        if (args->lstio_dbg_namep != NULL) {
                LIBCFS_ALLOC(name, args->lstio_dbg_nmlen + 1);
                if (name == NULL)
                        return -ENOMEM;

                if (cfs_copy_from_user(name, args->lstio_dbg_namep,
                                       args->lstio_dbg_nmlen)) {
                        LIBCFS_FREE(name, args->lstio_dbg_nmlen + 1);

                        return -EFAULT;
                }

                name[args->lstio_dbg_nmlen] = 0;
        }

        rc = -EINVAL;

        switch (args->lstio_dbg_type) {
        case LST_OPC_SESSION:
                rc = lstcon_session_debug(args->lstio_dbg_timeout,
                                          args->lstio_dbg_resultp);
                break;

        case LST_OPC_BATCHSRV:
                client = 0;
        case LST_OPC_BATCHCLI:
                if (name == NULL)
                        goto out;

                rc = lstcon_batch_debug(args->lstio_dbg_timeout,
                                        name, client, args->lstio_dbg_resultp);
                break;

        case LST_OPC_GROUP:
                if (name == NULL)
                        goto out;

                rc = lstcon_group_debug(args->lstio_dbg_timeout,
                                        name, args->lstio_dbg_resultp);
                break;

        case LST_OPC_NODES:
                if (args->lstio_dbg_count <= 0 ||
                    args->lstio_dbg_idsp == NULL)
                        goto out;

                rc = lstcon_nodes_debug(args->lstio_dbg_timeout,
                                        args->lstio_dbg_count,
                                        args->lstio_dbg_idsp,
                                        args->lstio_dbg_resultp);
                break;

        default:
                break;
        }

out:
        if (name != NULL)
                LIBCFS_FREE(name, args->lstio_dbg_nmlen + 1);

        return rc;
}
Exemplo n.º 19
0
static
int ctx_init_pack_request(struct obd_import *imp,
                          struct ptlrpc_request *req,
                          int lustre_srv,
                          uid_t uid, gid_t gid,
                          long token_size,
                          char __user *token)
{
        struct lustre_msg       *msg = req->rq_reqbuf;
        struct gss_sec          *gsec;
        struct gss_header       *ghdr;
        struct ptlrpc_user_desc *pud;
        __u32                   *p, size, offset = 2;
        rawobj_t                 obj;

        LASSERT(msg->lm_bufcount <= 4);
        LASSERT(req->rq_cli_ctx);
        LASSERT(req->rq_cli_ctx->cc_sec);

        /* gss hdr */
        ghdr = lustre_msg_buf(msg, 0, sizeof(*ghdr));
        ghdr->gh_version = PTLRPC_GSS_VERSION;
        ghdr->gh_sp = (__u8) imp->imp_sec->ps_part;
        ghdr->gh_flags = 0;
        ghdr->gh_proc = PTLRPC_GSS_PROC_INIT;
        ghdr->gh_seq = 0;
        ghdr->gh_svc = SPTLRPC_SVC_NULL;
        ghdr->gh_handle.len = 0;

        /* fix the user desc */
        if (req->rq_pack_udesc) {
                ghdr->gh_flags |= LUSTRE_GSS_PACK_USER;

                pud = lustre_msg_buf(msg, offset, sizeof(*pud));
                LASSERT(pud);
                pud->pud_uid = pud->pud_fsuid = uid;
                pud->pud_gid = pud->pud_fsgid = gid;
                pud->pud_cap = 0;
                pud->pud_ngroups = 0;
                offset++;
        }

        /* security payload */
        p = lustre_msg_buf(msg, offset, 0);
        size = msg->lm_buflens[offset];
        LASSERT(p);

        /* 1. lustre svc type */
        LASSERT(size > 4);
        *p++ = cpu_to_le32(lustre_srv);
        size -= 4;

        /* 2. target uuid */
        obj.len = strlen(imp->imp_obd->u.cli.cl_target_uuid.uuid) + 1;
        obj.data = imp->imp_obd->u.cli.cl_target_uuid.uuid;
        if (rawobj_serialize(&obj, &p, &size))
                LBUG();

        /* 3. reverse context handle. actually only needed by root user,
         *    but we send it anyway. */
        gsec = sec2gsec(req->rq_cli_ctx->cc_sec);
        obj.len = sizeof(gsec->gs_rvs_hdl);
        obj.data = (__u8 *) &gsec->gs_rvs_hdl;
        if (rawobj_serialize(&obj, &p, &size))
                LBUG();

        /* 4. now the token */
        LASSERT(size >= (sizeof(__u32) + token_size));
        *p++ = cpu_to_le32(((__u32) token_size));
        if (cfs_copy_from_user(p, token, token_size)) {
                CERROR("can't copy token\n");
                return -EFAULT;
        }
        size -= sizeof(__u32) + cfs_size_round4(token_size);

        req->rq_reqdata_len = lustre_shrink_msg(req->rq_reqbuf, offset,
                                                msg->lm_buflens[offset] - size, 0);
        return 0;
}
Exemplo n.º 20
0
static int __lov_setstripe(struct obd_export *exp, int max_lmm_size,
                           struct lov_stripe_md **lsmp,
                           struct lov_user_md *lump)
{
    struct obd_device *obd = class_exp2obd(exp);
    struct lov_obd *lov = &obd->u.lov;
    char buffer[sizeof(struct lov_user_md_v3)];
    struct lov_user_md_v3 *lumv3 = (struct lov_user_md_v3 *)&buffer[0];
    struct lov_user_md_v1 *lumv1 = (struct lov_user_md_v1 *)&buffer[0];
    int lmm_magic;
    int stripe_count;
    int rc;
    ENTRY;

    if (cfs_copy_from_user(lumv3, lump, sizeof(struct lov_user_md_v1)))
        RETURN(-EFAULT);

    lmm_magic = lumv1->lmm_magic;

    if (lmm_magic == __swab32(LOV_USER_MAGIC_V1)) {
        lustre_swab_lov_user_md_v1(lumv1);
        lmm_magic = LOV_USER_MAGIC_V1;
    } else if (lmm_magic == LOV_USER_MAGIC_V3) {
        if (cfs_copy_from_user(lumv3, lump, sizeof(*lumv3)))
            RETURN(-EFAULT);
    } else if (lmm_magic == __swab32(LOV_USER_MAGIC_V3)) {
        if (cfs_copy_from_user(lumv3, lump, sizeof(*lumv3)))
            RETURN(-EFAULT);
        lustre_swab_lov_user_md_v3(lumv3);
        lmm_magic = LOV_USER_MAGIC_V3;
    } else if (lmm_magic != LOV_USER_MAGIC_V1) {
        CDEBUG(D_IOCTL,
               "bad userland LOV MAGIC: %#08x != %#08x nor %#08x\n",
               lmm_magic, LOV_USER_MAGIC_V1, LOV_USER_MAGIC_V3);
        RETURN(-EINVAL);
    }

    /* in the rest of the tests, as *lumv1 and lumv3 have the same
     * fields, we use lumv1 to avoid code duplication */

    if (lumv1->lmm_pattern == 0) {
        lumv1->lmm_pattern = lov->desc.ld_pattern ?
                             lov->desc.ld_pattern : LOV_PATTERN_RAID0;
    }

    if (lumv1->lmm_pattern != LOV_PATTERN_RAID0) {
        CDEBUG(D_IOCTL, "bad userland stripe pattern: %#x\n",
               lumv1->lmm_pattern);
        RETURN(-EINVAL);
    }

    /* 64kB is the largest common page size we see (ia64), and matches the
     * check in lfs */
    if (lumv1->lmm_stripe_size & (LOV_MIN_STRIPE_SIZE - 1)) {
        CDEBUG(D_IOCTL, "stripe size %u not multiple of %u, fixing\n",
               lumv1->lmm_stripe_size, LOV_MIN_STRIPE_SIZE);
        lumv1->lmm_stripe_size = LOV_MIN_STRIPE_SIZE;
    }

    if ((lumv1->lmm_stripe_offset >= lov->desc.ld_tgt_count) &&
            (lumv1->lmm_stripe_offset !=
             (typeof(lumv1->lmm_stripe_offset))(-1))) {
        CDEBUG(D_IOCTL, "stripe offset %u > number of OSTs %u\n",
               lumv1->lmm_stripe_offset, lov->desc.ld_tgt_count);
        RETURN(-EINVAL);
    }
    stripe_count = lov_get_stripecnt(lov, lumv1->lmm_stripe_count);

    if (max_lmm_size) {
        int max_stripes = (max_lmm_size -
                           lov_mds_md_size(0, lmm_magic)) /
                          sizeof(struct lov_ost_data_v1);
        if (unlikely(max_stripes < stripe_count)) {
            CDEBUG(D_IOCTL, "stripe count reset from %d to %d\n",
                   stripe_count, max_stripes);
            stripe_count = max_stripes;
        }
    }

    if (lmm_magic == LOV_USER_MAGIC_V3) {
        struct pool_desc *pool;

        pool = lov_find_pool(lov, lumv3->lmm_pool_name);
        if (pool != NULL) {
            if (lumv3->lmm_stripe_offset !=
                    (typeof(lumv3->lmm_stripe_offset))(-1)) {
                rc = lov_check_index_in_pool(
                         lumv3->lmm_stripe_offset, pool);
                if (rc < 0) {
                    lov_pool_putref(pool);
                    RETURN(-EINVAL);
                }
            }

            if (stripe_count > pool_tgt_count(pool))
                stripe_count = pool_tgt_count(pool);

            lov_pool_putref(pool);
        }
    }

    rc = lov_alloc_memmd(lsmp, stripe_count, lumv1->lmm_pattern, lmm_magic);

    if (rc >= 0) {
        (*lsmp)->lsm_oinfo[0]->loi_ost_idx = lumv1->lmm_stripe_offset;
        (*lsmp)->lsm_stripe_size = lumv1->lmm_stripe_size;
        if (lmm_magic == LOV_USER_MAGIC_V3)
            strncpy((*lsmp)->lsm_pool_name, lumv3->lmm_pool_name,
                    LOV_MAXPOOLNAME);
        rc = 0;
    }

    RETURN(rc);
}
Exemplo n.º 21
0
/* Retrieve object striping information.
 *
 * @lump is a pointer to an in-core struct with lmm_ost_count indicating
 * the maximum number of OST indices which will fit in the user buffer.
 * lmm_magic must be LOV_USER_MAGIC.
 */
int lov_getstripe(struct obd_export *exp, struct lov_stripe_md *lsm,
                  struct lov_user_md *lump)
{
    /*
     * XXX huge struct allocated on stack.
     */
    /* we use lov_user_md_v3 because it is larger than lov_user_md_v1 */
    struct lov_user_md_v3 lum;
    struct lov_mds_md *lmmk = NULL;
    int rc, lmm_size;
    int lum_size;
    mm_segment_t seg;
    ENTRY;

    if (!lsm)
        RETURN(-ENODATA);

    /*
     * "Switch to kernel segment" to allow copying from kernel space by
     * copy_{to,from}_user().
     */
    seg = get_fs();
    set_fs(KERNEL_DS);

    /* we only need the header part from user space to get lmm_magic and
     * lmm_stripe_count, (the header part is common to v1 and v3) */
    lum_size = sizeof(struct lov_user_md_v1);
    if (cfs_copy_from_user(&lum, lump, lum_size))
        GOTO(out_set, rc = -EFAULT);
    else if ((lum.lmm_magic != LOV_USER_MAGIC) &&
             (lum.lmm_magic != LOV_USER_MAGIC_V3))
        GOTO(out_set, rc = -EINVAL);

    if (lum.lmm_stripe_count &&
            (lum.lmm_stripe_count < lsm->lsm_stripe_count)) {
        /* Return right size of stripe to user */
        lum.lmm_stripe_count = lsm->lsm_stripe_count;
        rc = cfs_copy_to_user(lump, &lum, lum_size);
        GOTO(out_set, rc = -EOVERFLOW);
    }
    rc = lov_packmd(exp, &lmmk, lsm);
    if (rc < 0)
        GOTO(out_set, rc);
    lmm_size = rc;
    rc = 0;

    /* FIXME: Bug 1185 - copy fields properly when structs change */
    /* struct lov_user_md_v3 and struct lov_mds_md_v3 must be the same */
    CLASSERT(sizeof(lum) == sizeof(struct lov_mds_md_v3));
    CLASSERT(sizeof lum.lmm_objects[0] == sizeof lmmk->lmm_objects[0]);

    if ((cpu_to_le32(LOV_MAGIC) != LOV_MAGIC) &&
            ((lmmk->lmm_magic == cpu_to_le32(LOV_MAGIC_V1)) ||
             (lmmk->lmm_magic == cpu_to_le32(LOV_MAGIC_V3)))) {
        lustre_swab_lov_mds_md(lmmk);
        lustre_swab_lov_user_md_objects(
            (struct lov_user_ost_data*)lmmk->lmm_objects,
            lmmk->lmm_stripe_count);
    }
    if (lum.lmm_magic == LOV_USER_MAGIC) {
        /* User request for v1, we need skip lmm_pool_name */
        if (lmmk->lmm_magic == LOV_MAGIC_V3) {
            memmove((char*)(&lmmk->lmm_stripe_count) +
                    sizeof(lmmk->lmm_stripe_count),
                    ((struct lov_mds_md_v3*)lmmk)->lmm_objects,
                    lmmk->lmm_stripe_count *
                    sizeof(struct lov_ost_data_v1));
            lmm_size -= LOV_MAXPOOLNAME;
        }
    } else {
        /* if v3 we just have to update the lum_size */
        lum_size = sizeof(struct lov_user_md_v3);
    }

    /* User wasn't expecting this many OST entries */
    if (lum.lmm_stripe_count == 0)
        lmm_size = lum_size;
    else if (lum.lmm_stripe_count < lmmk->lmm_stripe_count)
        GOTO(out_set, rc = -EOVERFLOW);
    /*
     * Have a difference between lov_mds_md & lov_user_md.
     * So we have to re-order the data before copy to user.
     */
    lum.lmm_stripe_count = lmmk->lmm_stripe_count;
    ((struct lov_user_md*)lmmk)->lmm_stripe_offset = 0;
    ((struct lov_user_md*)lmmk)->lmm_stripe_count = lum.lmm_stripe_count;
    if (cfs_copy_to_user(lump, lmmk, lmm_size))
        rc = -EFAULT;

    obd_free_diskmd(exp, &lmmk);
out_set:
    set_fs(seg);
    RETURN(rc);
}
Exemplo n.º 22
0
int gss_do_ctx_init_rpc(__user char *buffer, unsigned long count)
{
        struct obd_import        *imp;
        struct ptlrpc_request    *req;
        struct lgssd_ioctl_param  param;
        struct obd_device        *obd;
        char                      obdname[64];
        long                      lsize;
        int                       rc;

        if (count != sizeof(param)) {
                CERROR("ioctl size %lu, expect %lu, please check lgss_keyring "
                       "version\n", count, (unsigned long) sizeof(param));
                RETURN(-EINVAL);
        }
        if (cfs_copy_from_user(&param, buffer, sizeof(param))) {
                CERROR("failed copy data from lgssd\n");
                RETURN(-EFAULT);
        }

        if (param.version != GSSD_INTERFACE_VERSION) {
                CERROR("gssd interface version %d (expect %d)\n",
                        param.version, GSSD_INTERFACE_VERSION);
                RETURN(-EINVAL);
        }

        /* take name */
        if (strncpy_from_user(obdname, param.uuid, sizeof(obdname)) <= 0) {
                CERROR("Invalid obdname pointer\n");
                RETURN(-EFAULT);
        }

        obd = class_name2obd(obdname);
        if (!obd) {
                CERROR("no such obd %s\n", obdname);
                RETURN(-EINVAL);
        }

        if (unlikely(!obd->obd_set_up)) {
                CERROR("obd %s not setup\n", obdname);
                RETURN(-EINVAL);
        }

        cfs_spin_lock(&obd->obd_dev_lock);
        if (obd->obd_stopping) {
                CERROR("obd %s has stopped\n", obdname);
                cfs_spin_unlock(&obd->obd_dev_lock);
                RETURN(-EINVAL);
        }

        if (strcmp(obd->obd_type->typ_name, LUSTRE_MDC_NAME) &&
            strcmp(obd->obd_type->typ_name, LUSTRE_OSC_NAME) &&
            strcmp(obd->obd_type->typ_name, LUSTRE_MGC_NAME)) {
                CERROR("obd %s is not a client device\n", obdname);
                cfs_spin_unlock(&obd->obd_dev_lock);
                RETURN(-EINVAL);
        }
        cfs_spin_unlock(&obd->obd_dev_lock);

        cfs_down_read(&obd->u.cli.cl_sem);
        if (obd->u.cli.cl_import == NULL) {
                CERROR("obd %s: import has gone\n", obd->obd_name);
                cfs_up_read(&obd->u.cli.cl_sem);
                RETURN(-EINVAL);
        }
        imp = class_import_get(obd->u.cli.cl_import);
        cfs_up_read(&obd->u.cli.cl_sem);

        if (imp->imp_deactive) {
                CERROR("import has been deactivated\n");
                class_import_put(imp);
                RETURN(-EINVAL);
        }

        req = ptlrpc_request_alloc_pack(imp, &RQF_SEC_CTX, LUSTRE_OBD_VERSION,
                                        SEC_CTX_INIT);
        if (req == NULL) {
                param.status = -ENOMEM;
                goto out_copy;
        }

        if (req->rq_cli_ctx->cc_sec->ps_id != param.secid) {
                CWARN("original secid %d, now has changed to %d, "
                      "cancel this negotiation\n", param.secid,
                      req->rq_cli_ctx->cc_sec->ps_id);
                param.status = -EINVAL;
                goto out_copy;
        }

        /* get token */
        rc = ctx_init_pack_request(imp, req,
                                   param.lustre_svc,
                                   param.uid, param.gid,
                                   param.send_token_size,
                                   param.send_token);
        if (rc) {
                param.status = rc;
                goto out_copy;
        }

        ptlrpc_request_set_replen(req);

        rc = ptlrpc_queue_wait(req);
        if (rc) {
                /* If any _real_ denial be made, we expect server return
                 * -EACCES reply or return success but indicate gss error
                 * inside reply messsage. All other errors are treated as
                 * timeout, caller might try the negotiation repeatedly,
                 * leave recovery decisions to general ptlrpc layer.
                 *
                 * FIXME maybe some other error code shouldn't be treated
                 * as timeout. */
                param.status = rc;
                if (rc != -EACCES)
                        param.status = -ETIMEDOUT;
                goto out_copy;
        }

        LASSERT(req->rq_repdata);
        lsize = ctx_init_parse_reply(req->rq_repdata,
                                     ptlrpc_rep_need_swab(req),
                                     param.reply_buf, param.reply_buf_size);
        if (lsize < 0) {
                param.status = (int) lsize;
                goto out_copy;
        }

        param.status = 0;
        param.reply_length = lsize;

out_copy:
        if (cfs_copy_to_user(buffer, &param, sizeof(param)))
                rc = -EFAULT;
        else
                rc = 0;

        class_import_put(imp);
        ptlrpc_req_finished(req);
        RETURN(rc);
}