static int rbd_parse_param(struct fs_parameter *param,
			    struct rbd_parse_opts_ctx *pctx)
{
	struct rbd_options *opt = pctx->opts;
	struct fs_parse_result result;
	struct p_log log = {.prefix = "rbd"};
	int token, ret;

	ret = ceph_parse_param(param, pctx->copts, NULL);
	if (ret != -ENOPARAM)
		return ret;

	token = __fs_parse(&log, rbd_parameters, param, &result);
	dout("%s fs_parse '%s' token %d\n", __func__, param->key, token);
	if (token < 0) {
		if (token == -ENOPARAM)
			return inval_plog(&log, "Unknown parameter '%s'",
					  param->key);
		return token;
	}

	switch (token) {
	case Opt_queue_depth:
		if (result.uint_32 < 1)
			goto out_of_range;
		opt->queue_depth = result.uint_32;
		break;
	case Opt_alloc_size:
		if (result.uint_32 < SECTOR_SIZE)
			goto out_of_range;
		if (!is_power_of_2(result.uint_32))
			return inval_plog(&log, "alloc_size must be a power of 2");
		opt->alloc_size = result.uint_32;
		break;
	case Opt_lock_timeout:
		/* 0 is "wait forever" (i.e. infinite timeout) */
		if (result.uint_32 > INT_MAX / 1000)
			goto out_of_range;
		opt->lock_timeout = msecs_to_jiffies(result.uint_32 * 1000);
		break;
	case Opt_pool_ns:
		kfree(pctx->spec->pool_ns);
		pctx->spec->pool_ns = param->string;
		param->string = NULL;
		break;
	case Opt_compression_hint:
		switch (result.uint_32) {
		case Opt_compression_hint_none:
			opt->alloc_hint_flags &=
			    ~(CEPH_OSD_ALLOC_HINT_FLAG_COMPRESSIBLE |
			      CEPH_OSD_ALLOC_HINT_FLAG_INCOMPRESSIBLE);
			break;
		case Opt_compression_hint_compressible:
			opt->alloc_hint_flags |=
			    CEPH_OSD_ALLOC_HINT_FLAG_COMPRESSIBLE;
			opt->alloc_hint_flags &=
			    ~CEPH_OSD_ALLOC_HINT_FLAG_INCOMPRESSIBLE;
			break;
		case Opt_compression_hint_incompressible:
			opt->alloc_hint_flags |=
			    CEPH_OSD_ALLOC_HINT_FLAG_INCOMPRESSIBLE;
			opt->alloc_hint_flags &=
			    ~CEPH_OSD_ALLOC_HINT_FLAG_COMPRESSIBLE;
			break;
		default:
			BUG();
		}
		break;
	case Opt_read_only:
		opt->read_only = true;
		break;
	case Opt_read_write:
		opt->read_only = false;
		break;
	case Opt_lock_on_read:
		opt->lock_on_read = true;
		break;
	case Opt_exclusive:
		opt->exclusive = true;
		break;
	case Opt_notrim:
		opt->trim = false;
		break;
	default:
		BUG();
	}

	return 0;

out_of_range:
	return inval_plog(&log, "%s out of range", param->key);
}
static int rbd_parse_param(struct fs_parameter *param,
			    struct rbd_parse_opts_ctx *pctx)
{
	struct rbd_options *opt = pctx->opts;
	struct fs_parse_result result;
	struct p_log log = {.prefix = "rbd"};
	int token, ret;

	ret = ceph_parse_param(param, pctx->copts, NULL);
	if (ret != -ENOPARAM)
		return ret;

	token = __fs_parse(&log, rbd_parameters, param, &result);
	dout("%s fs_parse '%s' token %d\n", __func__, param->key, token);
	if (token < 0) {
		if (token == -ENOPARAM)
			return inval_plog(&log, "Unknown parameter '%s'",
					  param->key);
		return token;
	}

	switch (token) {
	case Opt_queue_depth:
		if (result.uint_32 < 1)
			goto out_of_range;
		opt->queue_depth = result.uint_32;
		break;
	case Opt_alloc_size:
		if (result.uint_32 < SECTOR_SIZE)
			goto out_of_range;
		if (!is_power_of_2(result.uint_32))
			return inval_plog(&log, "alloc_size must be a power of 2");
		opt->alloc_size = result.uint_32;
		break;
	case Opt_lock_timeout:
		 
		if (result.uint_32 > INT_MAX / 1000)
			goto out_of_range;
		opt->lock_timeout = msecs_to_jiffies(result.uint_32 * 1000);
		break;
	case Opt_pool_ns:
		kfree(pctx->spec->pool_ns);
		pctx->spec->pool_ns = param->string;
		param->string = NULL;
		break;
	case Opt_compression_hint:
		switch (result.uint_32) {
		case Opt_compression_hint_none:
			opt->alloc_hint_flags &=
			    ~(CEPH_OSD_ALLOC_HINT_FLAG_COMPRESSIBLE |
			      CEPH_OSD_ALLOC_HINT_FLAG_INCOMPRESSIBLE);
			break;
		case Opt_compression_hint_compressible:
			opt->alloc_hint_flags |=
			    CEPH_OSD_ALLOC_HINT_FLAG_COMPRESSIBLE;
			opt->alloc_hint_flags &=
			    ~CEPH_OSD_ALLOC_HINT_FLAG_INCOMPRESSIBLE;
			break;
		case Opt_compression_hint_incompressible:
			opt->alloc_hint_flags |=
			    CEPH_OSD_ALLOC_HINT_FLAG_INCOMPRESSIBLE;
			opt->alloc_hint_flags &=
			    ~CEPH_OSD_ALLOC_HINT_FLAG_COMPRESSIBLE;
			break;
		default:
			BUG();
		}
		break;
	case Opt_read_only:
		opt->read_only = true;
		break;
	case Opt_read_write:
		opt->read_only = false;
		break;
	case Opt_lock_on_read:
		opt->lock_on_read = true;
		break;
	case Opt_exclusive:
		opt->exclusive = true;
		break;
	case Opt_notrim:
		opt->trim = false;
		break;
	default:
		BUG();
	}

	return 0;

out_of_range:
	return inval_plog(&log, "%s out of range", param->key);
}