18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci#include <linux/ceph/ceph_debug.h>
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include <linux/backing-dev.h>
68c2ecf20Sopenharmony_ci#include <linux/ctype.h>
78c2ecf20Sopenharmony_ci#include <linux/fs.h>
88c2ecf20Sopenharmony_ci#include <linux/inet.h>
98c2ecf20Sopenharmony_ci#include <linux/in6.h>
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/mount.h>
128c2ecf20Sopenharmony_ci#include <linux/fs_context.h>
138c2ecf20Sopenharmony_ci#include <linux/fs_parser.h>
148c2ecf20Sopenharmony_ci#include <linux/sched.h>
158c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
168c2ecf20Sopenharmony_ci#include <linux/slab.h>
178c2ecf20Sopenharmony_ci#include <linux/statfs.h>
188c2ecf20Sopenharmony_ci#include <linux/string.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include "super.h"
218c2ecf20Sopenharmony_ci#include "mds_client.h"
228c2ecf20Sopenharmony_ci#include "cache.h"
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include <linux/ceph/ceph_features.h>
258c2ecf20Sopenharmony_ci#include <linux/ceph/decode.h>
268c2ecf20Sopenharmony_ci#include <linux/ceph/mon_client.h>
278c2ecf20Sopenharmony_ci#include <linux/ceph/auth.h>
288c2ecf20Sopenharmony_ci#include <linux/ceph/debugfs.h>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(ceph_fsc_lock);
318c2ecf20Sopenharmony_cistatic LIST_HEAD(ceph_fsc_list);
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci/*
348c2ecf20Sopenharmony_ci * Ceph superblock operations
358c2ecf20Sopenharmony_ci *
368c2ecf20Sopenharmony_ci * Handle the basics of mounting, unmounting.
378c2ecf20Sopenharmony_ci */
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci/*
408c2ecf20Sopenharmony_ci * super ops
418c2ecf20Sopenharmony_ci */
428c2ecf20Sopenharmony_cistatic void ceph_put_super(struct super_block *s)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	struct ceph_fs_client *fsc = ceph_sb_to_client(s);
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	dout("put_super\n");
478c2ecf20Sopenharmony_ci	ceph_mdsc_close_sessions(fsc->mdsc);
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic int ceph_statfs(struct dentry *dentry, struct kstatfs *buf)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	struct ceph_fs_client *fsc = ceph_inode_to_client(d_inode(dentry));
538c2ecf20Sopenharmony_ci	struct ceph_mon_client *monc = &fsc->client->monc;
548c2ecf20Sopenharmony_ci	struct ceph_statfs st;
558c2ecf20Sopenharmony_ci	int i, err;
568c2ecf20Sopenharmony_ci	u64 data_pool;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	if (fsc->mdsc->mdsmap->m_num_data_pg_pools == 1) {
598c2ecf20Sopenharmony_ci		data_pool = fsc->mdsc->mdsmap->m_data_pg_pools[0];
608c2ecf20Sopenharmony_ci	} else {
618c2ecf20Sopenharmony_ci		data_pool = CEPH_NOPOOL;
628c2ecf20Sopenharmony_ci	}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	dout("statfs\n");
658c2ecf20Sopenharmony_ci	err = ceph_monc_do_statfs(monc, data_pool, &st);
668c2ecf20Sopenharmony_ci	if (err < 0)
678c2ecf20Sopenharmony_ci		return err;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	/* fill in kstatfs */
708c2ecf20Sopenharmony_ci	buf->f_type = CEPH_SUPER_MAGIC;  /* ?? */
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	/*
738c2ecf20Sopenharmony_ci	 * express utilization in terms of large blocks to avoid
748c2ecf20Sopenharmony_ci	 * overflow on 32-bit machines.
758c2ecf20Sopenharmony_ci	 *
768c2ecf20Sopenharmony_ci	 * NOTE: for the time being, we make bsize == frsize to humor
778c2ecf20Sopenharmony_ci	 * not-yet-ancient versions of glibc that are broken.
788c2ecf20Sopenharmony_ci	 * Someday, we will probably want to report a real block
798c2ecf20Sopenharmony_ci	 * size...  whatever that may mean for a network file system!
808c2ecf20Sopenharmony_ci	 */
818c2ecf20Sopenharmony_ci	buf->f_bsize = 1 << CEPH_BLOCK_SHIFT;
828c2ecf20Sopenharmony_ci	buf->f_frsize = 1 << CEPH_BLOCK_SHIFT;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	/*
858c2ecf20Sopenharmony_ci	 * By default use root quota for stats; fallback to overall filesystem
868c2ecf20Sopenharmony_ci	 * usage if using 'noquotadf' mount option or if the root dir doesn't
878c2ecf20Sopenharmony_ci	 * have max_bytes quota set.
888c2ecf20Sopenharmony_ci	 */
898c2ecf20Sopenharmony_ci	if (ceph_test_mount_opt(fsc, NOQUOTADF) ||
908c2ecf20Sopenharmony_ci	    !ceph_quota_update_statfs(fsc, buf)) {
918c2ecf20Sopenharmony_ci		buf->f_blocks = le64_to_cpu(st.kb) >> (CEPH_BLOCK_SHIFT-10);
928c2ecf20Sopenharmony_ci		buf->f_bfree = le64_to_cpu(st.kb_avail) >> (CEPH_BLOCK_SHIFT-10);
938c2ecf20Sopenharmony_ci		buf->f_bavail = le64_to_cpu(st.kb_avail) >> (CEPH_BLOCK_SHIFT-10);
948c2ecf20Sopenharmony_ci	}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	buf->f_files = le64_to_cpu(st.num_objects);
978c2ecf20Sopenharmony_ci	buf->f_ffree = -1;
988c2ecf20Sopenharmony_ci	buf->f_namelen = NAME_MAX;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	/* Must convert the fsid, for consistent values across arches */
1018c2ecf20Sopenharmony_ci	buf->f_fsid.val[0] = 0;
1028c2ecf20Sopenharmony_ci	mutex_lock(&monc->mutex);
1038c2ecf20Sopenharmony_ci	for (i = 0 ; i < sizeof(monc->monmap->fsid) / sizeof(__le32) ; ++i)
1048c2ecf20Sopenharmony_ci		buf->f_fsid.val[0] ^= le32_to_cpu(((__le32 *)&monc->monmap->fsid)[i]);
1058c2ecf20Sopenharmony_ci	mutex_unlock(&monc->mutex);
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	/* fold the fs_cluster_id into the upper bits */
1088c2ecf20Sopenharmony_ci	buf->f_fsid.val[1] = monc->fs_cluster_id;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	return 0;
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic int ceph_sync_fs(struct super_block *sb, int wait)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	struct ceph_fs_client *fsc = ceph_sb_to_client(sb);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	if (!wait) {
1188c2ecf20Sopenharmony_ci		dout("sync_fs (non-blocking)\n");
1198c2ecf20Sopenharmony_ci		ceph_flush_dirty_caps(fsc->mdsc);
1208c2ecf20Sopenharmony_ci		dout("sync_fs (non-blocking) done\n");
1218c2ecf20Sopenharmony_ci		return 0;
1228c2ecf20Sopenharmony_ci	}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	dout("sync_fs (blocking)\n");
1258c2ecf20Sopenharmony_ci	ceph_osdc_sync(&fsc->client->osdc);
1268c2ecf20Sopenharmony_ci	ceph_mdsc_sync(fsc->mdsc);
1278c2ecf20Sopenharmony_ci	dout("sync_fs (blocking) done\n");
1288c2ecf20Sopenharmony_ci	return 0;
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci/*
1328c2ecf20Sopenharmony_ci * mount options
1338c2ecf20Sopenharmony_ci */
1348c2ecf20Sopenharmony_cienum {
1358c2ecf20Sopenharmony_ci	Opt_wsize,
1368c2ecf20Sopenharmony_ci	Opt_rsize,
1378c2ecf20Sopenharmony_ci	Opt_rasize,
1388c2ecf20Sopenharmony_ci	Opt_caps_wanted_delay_min,
1398c2ecf20Sopenharmony_ci	Opt_caps_wanted_delay_max,
1408c2ecf20Sopenharmony_ci	Opt_caps_max,
1418c2ecf20Sopenharmony_ci	Opt_readdir_max_entries,
1428c2ecf20Sopenharmony_ci	Opt_readdir_max_bytes,
1438c2ecf20Sopenharmony_ci	Opt_congestion_kb,
1448c2ecf20Sopenharmony_ci	/* int args above */
1458c2ecf20Sopenharmony_ci	Opt_snapdirname,
1468c2ecf20Sopenharmony_ci	Opt_mds_namespace,
1478c2ecf20Sopenharmony_ci	Opt_recover_session,
1488c2ecf20Sopenharmony_ci	Opt_source,
1498c2ecf20Sopenharmony_ci	/* string args above */
1508c2ecf20Sopenharmony_ci	Opt_dirstat,
1518c2ecf20Sopenharmony_ci	Opt_rbytes,
1528c2ecf20Sopenharmony_ci	Opt_asyncreaddir,
1538c2ecf20Sopenharmony_ci	Opt_dcache,
1548c2ecf20Sopenharmony_ci	Opt_ino32,
1558c2ecf20Sopenharmony_ci	Opt_fscache,
1568c2ecf20Sopenharmony_ci	Opt_poolperm,
1578c2ecf20Sopenharmony_ci	Opt_require_active_mds,
1588c2ecf20Sopenharmony_ci	Opt_acl,
1598c2ecf20Sopenharmony_ci	Opt_quotadf,
1608c2ecf20Sopenharmony_ci	Opt_copyfrom,
1618c2ecf20Sopenharmony_ci	Opt_wsync,
1628c2ecf20Sopenharmony_ci};
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cienum ceph_recover_session_mode {
1658c2ecf20Sopenharmony_ci	ceph_recover_session_no,
1668c2ecf20Sopenharmony_ci	ceph_recover_session_clean
1678c2ecf20Sopenharmony_ci};
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistatic const struct constant_table ceph_param_recover[] = {
1708c2ecf20Sopenharmony_ci	{ "no",		ceph_recover_session_no },
1718c2ecf20Sopenharmony_ci	{ "clean",	ceph_recover_session_clean },
1728c2ecf20Sopenharmony_ci	{}
1738c2ecf20Sopenharmony_ci};
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cistatic const struct fs_parameter_spec ceph_mount_parameters[] = {
1768c2ecf20Sopenharmony_ci	fsparam_flag_no ("acl",				Opt_acl),
1778c2ecf20Sopenharmony_ci	fsparam_flag_no ("asyncreaddir",		Opt_asyncreaddir),
1788c2ecf20Sopenharmony_ci	fsparam_s32	("caps_max",			Opt_caps_max),
1798c2ecf20Sopenharmony_ci	fsparam_u32	("caps_wanted_delay_max",	Opt_caps_wanted_delay_max),
1808c2ecf20Sopenharmony_ci	fsparam_u32	("caps_wanted_delay_min",	Opt_caps_wanted_delay_min),
1818c2ecf20Sopenharmony_ci	fsparam_u32	("write_congestion_kb",		Opt_congestion_kb),
1828c2ecf20Sopenharmony_ci	fsparam_flag_no ("copyfrom",			Opt_copyfrom),
1838c2ecf20Sopenharmony_ci	fsparam_flag_no ("dcache",			Opt_dcache),
1848c2ecf20Sopenharmony_ci	fsparam_flag_no ("dirstat",			Opt_dirstat),
1858c2ecf20Sopenharmony_ci	fsparam_flag_no	("fsc",				Opt_fscache), // fsc|nofsc
1868c2ecf20Sopenharmony_ci	fsparam_string	("fsc",				Opt_fscache), // fsc=...
1878c2ecf20Sopenharmony_ci	fsparam_flag_no ("ino32",			Opt_ino32),
1888c2ecf20Sopenharmony_ci	fsparam_string	("mds_namespace",		Opt_mds_namespace),
1898c2ecf20Sopenharmony_ci	fsparam_flag_no ("poolperm",			Opt_poolperm),
1908c2ecf20Sopenharmony_ci	fsparam_flag_no ("quotadf",			Opt_quotadf),
1918c2ecf20Sopenharmony_ci	fsparam_u32	("rasize",			Opt_rasize),
1928c2ecf20Sopenharmony_ci	fsparam_flag_no ("rbytes",			Opt_rbytes),
1938c2ecf20Sopenharmony_ci	fsparam_u32	("readdir_max_bytes",		Opt_readdir_max_bytes),
1948c2ecf20Sopenharmony_ci	fsparam_u32	("readdir_max_entries",		Opt_readdir_max_entries),
1958c2ecf20Sopenharmony_ci	fsparam_enum	("recover_session",		Opt_recover_session, ceph_param_recover),
1968c2ecf20Sopenharmony_ci	fsparam_flag_no ("require_active_mds",		Opt_require_active_mds),
1978c2ecf20Sopenharmony_ci	fsparam_u32	("rsize",			Opt_rsize),
1988c2ecf20Sopenharmony_ci	fsparam_string	("snapdirname",			Opt_snapdirname),
1998c2ecf20Sopenharmony_ci	fsparam_string	("source",			Opt_source),
2008c2ecf20Sopenharmony_ci	fsparam_u32	("wsize",			Opt_wsize),
2018c2ecf20Sopenharmony_ci	fsparam_flag_no	("wsync",			Opt_wsync),
2028c2ecf20Sopenharmony_ci	{}
2038c2ecf20Sopenharmony_ci};
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistruct ceph_parse_opts_ctx {
2068c2ecf20Sopenharmony_ci	struct ceph_options		*copts;
2078c2ecf20Sopenharmony_ci	struct ceph_mount_options	*opts;
2088c2ecf20Sopenharmony_ci};
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci/*
2118c2ecf20Sopenharmony_ci * Remove adjacent slashes and then the trailing slash, unless it is
2128c2ecf20Sopenharmony_ci * the only remaining character.
2138c2ecf20Sopenharmony_ci *
2148c2ecf20Sopenharmony_ci * E.g. "//dir1////dir2///" --> "/dir1/dir2", "///" --> "/".
2158c2ecf20Sopenharmony_ci */
2168c2ecf20Sopenharmony_cistatic void canonicalize_path(char *path)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	int i, j = 0;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	for (i = 0; path[i] != '\0'; i++) {
2218c2ecf20Sopenharmony_ci		if (path[i] != '/' || j < 1 || path[j - 1] != '/')
2228c2ecf20Sopenharmony_ci			path[j++] = path[i];
2238c2ecf20Sopenharmony_ci	}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	if (j > 1 && path[j - 1] == '/')
2268c2ecf20Sopenharmony_ci		j--;
2278c2ecf20Sopenharmony_ci	path[j] = '\0';
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci/*
2318c2ecf20Sopenharmony_ci * Parse the source parameter.  Distinguish the server list from the path.
2328c2ecf20Sopenharmony_ci *
2338c2ecf20Sopenharmony_ci * The source will look like:
2348c2ecf20Sopenharmony_ci *     <server_spec>[,<server_spec>...]:[<path>]
2358c2ecf20Sopenharmony_ci * where
2368c2ecf20Sopenharmony_ci *     <server_spec> is <ip>[:<port>]
2378c2ecf20Sopenharmony_ci *     <path> is optional, but if present must begin with '/'
2388c2ecf20Sopenharmony_ci */
2398c2ecf20Sopenharmony_cistatic int ceph_parse_source(struct fs_parameter *param, struct fs_context *fc)
2408c2ecf20Sopenharmony_ci{
2418c2ecf20Sopenharmony_ci	struct ceph_parse_opts_ctx *pctx = fc->fs_private;
2428c2ecf20Sopenharmony_ci	struct ceph_mount_options *fsopt = pctx->opts;
2438c2ecf20Sopenharmony_ci	char *dev_name = param->string, *dev_name_end;
2448c2ecf20Sopenharmony_ci	int ret;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	dout("%s '%s'\n", __func__, dev_name);
2478c2ecf20Sopenharmony_ci	if (!dev_name || !*dev_name)
2488c2ecf20Sopenharmony_ci		return invalfc(fc, "Empty source");
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	dev_name_end = strchr(dev_name, '/');
2518c2ecf20Sopenharmony_ci	if (dev_name_end) {
2528c2ecf20Sopenharmony_ci		/*
2538c2ecf20Sopenharmony_ci		 * The server_path will include the whole chars from userland
2548c2ecf20Sopenharmony_ci		 * including the leading '/'.
2558c2ecf20Sopenharmony_ci		 */
2568c2ecf20Sopenharmony_ci		kfree(fsopt->server_path);
2578c2ecf20Sopenharmony_ci		fsopt->server_path = kstrdup(dev_name_end, GFP_KERNEL);
2588c2ecf20Sopenharmony_ci		if (!fsopt->server_path)
2598c2ecf20Sopenharmony_ci			return -ENOMEM;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci		canonicalize_path(fsopt->server_path);
2628c2ecf20Sopenharmony_ci	} else {
2638c2ecf20Sopenharmony_ci		dev_name_end = dev_name + strlen(dev_name);
2648c2ecf20Sopenharmony_ci	}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	dev_name_end--;		/* back up to ':' separator */
2678c2ecf20Sopenharmony_ci	if (dev_name_end < dev_name || *dev_name_end != ':')
2688c2ecf20Sopenharmony_ci		return invalfc(fc, "No path or : separator in source");
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	dout("device name '%.*s'\n", (int)(dev_name_end - dev_name), dev_name);
2718c2ecf20Sopenharmony_ci	if (fsopt->server_path)
2728c2ecf20Sopenharmony_ci		dout("server path '%s'\n", fsopt->server_path);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	ret = ceph_parse_mon_ips(param->string, dev_name_end - dev_name,
2758c2ecf20Sopenharmony_ci				 pctx->copts, fc->log.log);
2768c2ecf20Sopenharmony_ci	if (ret)
2778c2ecf20Sopenharmony_ci		return ret;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	fc->source = param->string;
2808c2ecf20Sopenharmony_ci	param->string = NULL;
2818c2ecf20Sopenharmony_ci	return 0;
2828c2ecf20Sopenharmony_ci}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_cistatic int ceph_parse_mount_param(struct fs_context *fc,
2858c2ecf20Sopenharmony_ci				  struct fs_parameter *param)
2868c2ecf20Sopenharmony_ci{
2878c2ecf20Sopenharmony_ci	struct ceph_parse_opts_ctx *pctx = fc->fs_private;
2888c2ecf20Sopenharmony_ci	struct ceph_mount_options *fsopt = pctx->opts;
2898c2ecf20Sopenharmony_ci	struct fs_parse_result result;
2908c2ecf20Sopenharmony_ci	unsigned int mode;
2918c2ecf20Sopenharmony_ci	int token, ret;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	ret = ceph_parse_param(param, pctx->copts, fc->log.log);
2948c2ecf20Sopenharmony_ci	if (ret != -ENOPARAM)
2958c2ecf20Sopenharmony_ci		return ret;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	token = fs_parse(fc, ceph_mount_parameters, param, &result);
2988c2ecf20Sopenharmony_ci	dout("%s fs_parse '%s' token %d\n", __func__, param->key, token);
2998c2ecf20Sopenharmony_ci	if (token < 0)
3008c2ecf20Sopenharmony_ci		return token;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	switch (token) {
3038c2ecf20Sopenharmony_ci	case Opt_snapdirname:
3048c2ecf20Sopenharmony_ci		kfree(fsopt->snapdir_name);
3058c2ecf20Sopenharmony_ci		fsopt->snapdir_name = param->string;
3068c2ecf20Sopenharmony_ci		param->string = NULL;
3078c2ecf20Sopenharmony_ci		break;
3088c2ecf20Sopenharmony_ci	case Opt_mds_namespace:
3098c2ecf20Sopenharmony_ci		kfree(fsopt->mds_namespace);
3108c2ecf20Sopenharmony_ci		fsopt->mds_namespace = param->string;
3118c2ecf20Sopenharmony_ci		param->string = NULL;
3128c2ecf20Sopenharmony_ci		break;
3138c2ecf20Sopenharmony_ci	case Opt_recover_session:
3148c2ecf20Sopenharmony_ci		mode = result.uint_32;
3158c2ecf20Sopenharmony_ci		if (mode == ceph_recover_session_no)
3168c2ecf20Sopenharmony_ci			fsopt->flags &= ~CEPH_MOUNT_OPT_CLEANRECOVER;
3178c2ecf20Sopenharmony_ci		else if (mode == ceph_recover_session_clean)
3188c2ecf20Sopenharmony_ci			fsopt->flags |= CEPH_MOUNT_OPT_CLEANRECOVER;
3198c2ecf20Sopenharmony_ci		else
3208c2ecf20Sopenharmony_ci			BUG();
3218c2ecf20Sopenharmony_ci		break;
3228c2ecf20Sopenharmony_ci	case Opt_source:
3238c2ecf20Sopenharmony_ci		if (fc->source)
3248c2ecf20Sopenharmony_ci			return invalfc(fc, "Multiple sources specified");
3258c2ecf20Sopenharmony_ci		return ceph_parse_source(param, fc);
3268c2ecf20Sopenharmony_ci	case Opt_wsize:
3278c2ecf20Sopenharmony_ci		if (result.uint_32 < PAGE_SIZE ||
3288c2ecf20Sopenharmony_ci		    result.uint_32 > CEPH_MAX_WRITE_SIZE)
3298c2ecf20Sopenharmony_ci			goto out_of_range;
3308c2ecf20Sopenharmony_ci		fsopt->wsize = ALIGN(result.uint_32, PAGE_SIZE);
3318c2ecf20Sopenharmony_ci		break;
3328c2ecf20Sopenharmony_ci	case Opt_rsize:
3338c2ecf20Sopenharmony_ci		if (result.uint_32 < PAGE_SIZE ||
3348c2ecf20Sopenharmony_ci		    result.uint_32 > CEPH_MAX_READ_SIZE)
3358c2ecf20Sopenharmony_ci			goto out_of_range;
3368c2ecf20Sopenharmony_ci		fsopt->rsize = ALIGN(result.uint_32, PAGE_SIZE);
3378c2ecf20Sopenharmony_ci		break;
3388c2ecf20Sopenharmony_ci	case Opt_rasize:
3398c2ecf20Sopenharmony_ci		fsopt->rasize = ALIGN(result.uint_32, PAGE_SIZE);
3408c2ecf20Sopenharmony_ci		break;
3418c2ecf20Sopenharmony_ci	case Opt_caps_wanted_delay_min:
3428c2ecf20Sopenharmony_ci		if (result.uint_32 < 1)
3438c2ecf20Sopenharmony_ci			goto out_of_range;
3448c2ecf20Sopenharmony_ci		fsopt->caps_wanted_delay_min = result.uint_32;
3458c2ecf20Sopenharmony_ci		break;
3468c2ecf20Sopenharmony_ci	case Opt_caps_wanted_delay_max:
3478c2ecf20Sopenharmony_ci		if (result.uint_32 < 1)
3488c2ecf20Sopenharmony_ci			goto out_of_range;
3498c2ecf20Sopenharmony_ci		fsopt->caps_wanted_delay_max = result.uint_32;
3508c2ecf20Sopenharmony_ci		break;
3518c2ecf20Sopenharmony_ci	case Opt_caps_max:
3528c2ecf20Sopenharmony_ci		if (result.int_32 < 0)
3538c2ecf20Sopenharmony_ci			goto out_of_range;
3548c2ecf20Sopenharmony_ci		fsopt->caps_max = result.int_32;
3558c2ecf20Sopenharmony_ci		break;
3568c2ecf20Sopenharmony_ci	case Opt_readdir_max_entries:
3578c2ecf20Sopenharmony_ci		if (result.uint_32 < 1)
3588c2ecf20Sopenharmony_ci			goto out_of_range;
3598c2ecf20Sopenharmony_ci		fsopt->max_readdir = result.uint_32;
3608c2ecf20Sopenharmony_ci		break;
3618c2ecf20Sopenharmony_ci	case Opt_readdir_max_bytes:
3628c2ecf20Sopenharmony_ci		if (result.uint_32 < PAGE_SIZE && result.uint_32 != 0)
3638c2ecf20Sopenharmony_ci			goto out_of_range;
3648c2ecf20Sopenharmony_ci		fsopt->max_readdir_bytes = result.uint_32;
3658c2ecf20Sopenharmony_ci		break;
3668c2ecf20Sopenharmony_ci	case Opt_congestion_kb:
3678c2ecf20Sopenharmony_ci		if (result.uint_32 < 1024) /* at least 1M */
3688c2ecf20Sopenharmony_ci			goto out_of_range;
3698c2ecf20Sopenharmony_ci		fsopt->congestion_kb = result.uint_32;
3708c2ecf20Sopenharmony_ci		break;
3718c2ecf20Sopenharmony_ci	case Opt_dirstat:
3728c2ecf20Sopenharmony_ci		if (!result.negated)
3738c2ecf20Sopenharmony_ci			fsopt->flags |= CEPH_MOUNT_OPT_DIRSTAT;
3748c2ecf20Sopenharmony_ci		else
3758c2ecf20Sopenharmony_ci			fsopt->flags &= ~CEPH_MOUNT_OPT_DIRSTAT;
3768c2ecf20Sopenharmony_ci		break;
3778c2ecf20Sopenharmony_ci	case Opt_rbytes:
3788c2ecf20Sopenharmony_ci		if (!result.negated)
3798c2ecf20Sopenharmony_ci			fsopt->flags |= CEPH_MOUNT_OPT_RBYTES;
3808c2ecf20Sopenharmony_ci		else
3818c2ecf20Sopenharmony_ci			fsopt->flags &= ~CEPH_MOUNT_OPT_RBYTES;
3828c2ecf20Sopenharmony_ci		break;
3838c2ecf20Sopenharmony_ci	case Opt_asyncreaddir:
3848c2ecf20Sopenharmony_ci		if (!result.negated)
3858c2ecf20Sopenharmony_ci			fsopt->flags &= ~CEPH_MOUNT_OPT_NOASYNCREADDIR;
3868c2ecf20Sopenharmony_ci		else
3878c2ecf20Sopenharmony_ci			fsopt->flags |= CEPH_MOUNT_OPT_NOASYNCREADDIR;
3888c2ecf20Sopenharmony_ci		break;
3898c2ecf20Sopenharmony_ci	case Opt_dcache:
3908c2ecf20Sopenharmony_ci		if (!result.negated)
3918c2ecf20Sopenharmony_ci			fsopt->flags |= CEPH_MOUNT_OPT_DCACHE;
3928c2ecf20Sopenharmony_ci		else
3938c2ecf20Sopenharmony_ci			fsopt->flags &= ~CEPH_MOUNT_OPT_DCACHE;
3948c2ecf20Sopenharmony_ci		break;
3958c2ecf20Sopenharmony_ci	case Opt_ino32:
3968c2ecf20Sopenharmony_ci		if (!result.negated)
3978c2ecf20Sopenharmony_ci			fsopt->flags |= CEPH_MOUNT_OPT_INO32;
3988c2ecf20Sopenharmony_ci		else
3998c2ecf20Sopenharmony_ci			fsopt->flags &= ~CEPH_MOUNT_OPT_INO32;
4008c2ecf20Sopenharmony_ci		break;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	case Opt_fscache:
4038c2ecf20Sopenharmony_ci#ifdef CONFIG_CEPH_FSCACHE
4048c2ecf20Sopenharmony_ci		kfree(fsopt->fscache_uniq);
4058c2ecf20Sopenharmony_ci		fsopt->fscache_uniq = NULL;
4068c2ecf20Sopenharmony_ci		if (result.negated) {
4078c2ecf20Sopenharmony_ci			fsopt->flags &= ~CEPH_MOUNT_OPT_FSCACHE;
4088c2ecf20Sopenharmony_ci		} else {
4098c2ecf20Sopenharmony_ci			fsopt->flags |= CEPH_MOUNT_OPT_FSCACHE;
4108c2ecf20Sopenharmony_ci			fsopt->fscache_uniq = param->string;
4118c2ecf20Sopenharmony_ci			param->string = NULL;
4128c2ecf20Sopenharmony_ci		}
4138c2ecf20Sopenharmony_ci		break;
4148c2ecf20Sopenharmony_ci#else
4158c2ecf20Sopenharmony_ci		return invalfc(fc, "fscache support is disabled");
4168c2ecf20Sopenharmony_ci#endif
4178c2ecf20Sopenharmony_ci	case Opt_poolperm:
4188c2ecf20Sopenharmony_ci		if (!result.negated)
4198c2ecf20Sopenharmony_ci			fsopt->flags &= ~CEPH_MOUNT_OPT_NOPOOLPERM;
4208c2ecf20Sopenharmony_ci		else
4218c2ecf20Sopenharmony_ci			fsopt->flags |= CEPH_MOUNT_OPT_NOPOOLPERM;
4228c2ecf20Sopenharmony_ci		break;
4238c2ecf20Sopenharmony_ci	case Opt_require_active_mds:
4248c2ecf20Sopenharmony_ci		if (!result.negated)
4258c2ecf20Sopenharmony_ci			fsopt->flags &= ~CEPH_MOUNT_OPT_MOUNTWAIT;
4268c2ecf20Sopenharmony_ci		else
4278c2ecf20Sopenharmony_ci			fsopt->flags |= CEPH_MOUNT_OPT_MOUNTWAIT;
4288c2ecf20Sopenharmony_ci		break;
4298c2ecf20Sopenharmony_ci	case Opt_quotadf:
4308c2ecf20Sopenharmony_ci		if (!result.negated)
4318c2ecf20Sopenharmony_ci			fsopt->flags &= ~CEPH_MOUNT_OPT_NOQUOTADF;
4328c2ecf20Sopenharmony_ci		else
4338c2ecf20Sopenharmony_ci			fsopt->flags |= CEPH_MOUNT_OPT_NOQUOTADF;
4348c2ecf20Sopenharmony_ci		break;
4358c2ecf20Sopenharmony_ci	case Opt_copyfrom:
4368c2ecf20Sopenharmony_ci		if (!result.negated)
4378c2ecf20Sopenharmony_ci			fsopt->flags &= ~CEPH_MOUNT_OPT_NOCOPYFROM;
4388c2ecf20Sopenharmony_ci		else
4398c2ecf20Sopenharmony_ci			fsopt->flags |= CEPH_MOUNT_OPT_NOCOPYFROM;
4408c2ecf20Sopenharmony_ci		break;
4418c2ecf20Sopenharmony_ci	case Opt_acl:
4428c2ecf20Sopenharmony_ci		if (!result.negated) {
4438c2ecf20Sopenharmony_ci#ifdef CONFIG_CEPH_FS_POSIX_ACL
4448c2ecf20Sopenharmony_ci			fc->sb_flags |= SB_POSIXACL;
4458c2ecf20Sopenharmony_ci#else
4468c2ecf20Sopenharmony_ci			return invalfc(fc, "POSIX ACL support is disabled");
4478c2ecf20Sopenharmony_ci#endif
4488c2ecf20Sopenharmony_ci		} else {
4498c2ecf20Sopenharmony_ci			fc->sb_flags &= ~SB_POSIXACL;
4508c2ecf20Sopenharmony_ci		}
4518c2ecf20Sopenharmony_ci		break;
4528c2ecf20Sopenharmony_ci	case Opt_wsync:
4538c2ecf20Sopenharmony_ci		if (!result.negated)
4548c2ecf20Sopenharmony_ci			fsopt->flags &= ~CEPH_MOUNT_OPT_ASYNC_DIROPS;
4558c2ecf20Sopenharmony_ci		else
4568c2ecf20Sopenharmony_ci			fsopt->flags |= CEPH_MOUNT_OPT_ASYNC_DIROPS;
4578c2ecf20Sopenharmony_ci		break;
4588c2ecf20Sopenharmony_ci	default:
4598c2ecf20Sopenharmony_ci		BUG();
4608c2ecf20Sopenharmony_ci	}
4618c2ecf20Sopenharmony_ci	return 0;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ciout_of_range:
4648c2ecf20Sopenharmony_ci	return invalfc(fc, "%s out of range", param->key);
4658c2ecf20Sopenharmony_ci}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_cistatic void destroy_mount_options(struct ceph_mount_options *args)
4688c2ecf20Sopenharmony_ci{
4698c2ecf20Sopenharmony_ci	dout("destroy_mount_options %p\n", args);
4708c2ecf20Sopenharmony_ci	if (!args)
4718c2ecf20Sopenharmony_ci		return;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	kfree(args->snapdir_name);
4748c2ecf20Sopenharmony_ci	kfree(args->mds_namespace);
4758c2ecf20Sopenharmony_ci	kfree(args->server_path);
4768c2ecf20Sopenharmony_ci	kfree(args->fscache_uniq);
4778c2ecf20Sopenharmony_ci	kfree(args);
4788c2ecf20Sopenharmony_ci}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_cistatic int strcmp_null(const char *s1, const char *s2)
4818c2ecf20Sopenharmony_ci{
4828c2ecf20Sopenharmony_ci	if (!s1 && !s2)
4838c2ecf20Sopenharmony_ci		return 0;
4848c2ecf20Sopenharmony_ci	if (s1 && !s2)
4858c2ecf20Sopenharmony_ci		return -1;
4868c2ecf20Sopenharmony_ci	if (!s1 && s2)
4878c2ecf20Sopenharmony_ci		return 1;
4888c2ecf20Sopenharmony_ci	return strcmp(s1, s2);
4898c2ecf20Sopenharmony_ci}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_cistatic int compare_mount_options(struct ceph_mount_options *new_fsopt,
4928c2ecf20Sopenharmony_ci				 struct ceph_options *new_opt,
4938c2ecf20Sopenharmony_ci				 struct ceph_fs_client *fsc)
4948c2ecf20Sopenharmony_ci{
4958c2ecf20Sopenharmony_ci	struct ceph_mount_options *fsopt1 = new_fsopt;
4968c2ecf20Sopenharmony_ci	struct ceph_mount_options *fsopt2 = fsc->mount_options;
4978c2ecf20Sopenharmony_ci	int ofs = offsetof(struct ceph_mount_options, snapdir_name);
4988c2ecf20Sopenharmony_ci	int ret;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	ret = memcmp(fsopt1, fsopt2, ofs);
5018c2ecf20Sopenharmony_ci	if (ret)
5028c2ecf20Sopenharmony_ci		return ret;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	ret = strcmp_null(fsopt1->snapdir_name, fsopt2->snapdir_name);
5058c2ecf20Sopenharmony_ci	if (ret)
5068c2ecf20Sopenharmony_ci		return ret;
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	ret = strcmp_null(fsopt1->mds_namespace, fsopt2->mds_namespace);
5098c2ecf20Sopenharmony_ci	if (ret)
5108c2ecf20Sopenharmony_ci		return ret;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	ret = strcmp_null(fsopt1->server_path, fsopt2->server_path);
5138c2ecf20Sopenharmony_ci	if (ret)
5148c2ecf20Sopenharmony_ci		return ret;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	ret = strcmp_null(fsopt1->fscache_uniq, fsopt2->fscache_uniq);
5178c2ecf20Sopenharmony_ci	if (ret)
5188c2ecf20Sopenharmony_ci		return ret;
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	return ceph_compare_options(new_opt, fsc->client);
5218c2ecf20Sopenharmony_ci}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci/**
5248c2ecf20Sopenharmony_ci * ceph_show_options - Show mount options in /proc/mounts
5258c2ecf20Sopenharmony_ci * @m: seq_file to write to
5268c2ecf20Sopenharmony_ci * @root: root of that (sub)tree
5278c2ecf20Sopenharmony_ci */
5288c2ecf20Sopenharmony_cistatic int ceph_show_options(struct seq_file *m, struct dentry *root)
5298c2ecf20Sopenharmony_ci{
5308c2ecf20Sopenharmony_ci	struct ceph_fs_client *fsc = ceph_sb_to_client(root->d_sb);
5318c2ecf20Sopenharmony_ci	struct ceph_mount_options *fsopt = fsc->mount_options;
5328c2ecf20Sopenharmony_ci	size_t pos;
5338c2ecf20Sopenharmony_ci	int ret;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	/* a comma between MNT/MS and client options */
5368c2ecf20Sopenharmony_ci	seq_putc(m, ',');
5378c2ecf20Sopenharmony_ci	pos = m->count;
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	ret = ceph_print_client_options(m, fsc->client, false);
5408c2ecf20Sopenharmony_ci	if (ret)
5418c2ecf20Sopenharmony_ci		return ret;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	/* retract our comma if no client options */
5448c2ecf20Sopenharmony_ci	if (m->count == pos)
5458c2ecf20Sopenharmony_ci		m->count--;
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	if (fsopt->flags & CEPH_MOUNT_OPT_DIRSTAT)
5488c2ecf20Sopenharmony_ci		seq_puts(m, ",dirstat");
5498c2ecf20Sopenharmony_ci	if ((fsopt->flags & CEPH_MOUNT_OPT_RBYTES))
5508c2ecf20Sopenharmony_ci		seq_puts(m, ",rbytes");
5518c2ecf20Sopenharmony_ci	if (fsopt->flags & CEPH_MOUNT_OPT_NOASYNCREADDIR)
5528c2ecf20Sopenharmony_ci		seq_puts(m, ",noasyncreaddir");
5538c2ecf20Sopenharmony_ci	if ((fsopt->flags & CEPH_MOUNT_OPT_DCACHE) == 0)
5548c2ecf20Sopenharmony_ci		seq_puts(m, ",nodcache");
5558c2ecf20Sopenharmony_ci	if (fsopt->flags & CEPH_MOUNT_OPT_INO32)
5568c2ecf20Sopenharmony_ci		seq_puts(m, ",ino32");
5578c2ecf20Sopenharmony_ci	if (fsopt->flags & CEPH_MOUNT_OPT_FSCACHE) {
5588c2ecf20Sopenharmony_ci		seq_show_option(m, "fsc", fsopt->fscache_uniq);
5598c2ecf20Sopenharmony_ci	}
5608c2ecf20Sopenharmony_ci	if (fsopt->flags & CEPH_MOUNT_OPT_NOPOOLPERM)
5618c2ecf20Sopenharmony_ci		seq_puts(m, ",nopoolperm");
5628c2ecf20Sopenharmony_ci	if (fsopt->flags & CEPH_MOUNT_OPT_NOQUOTADF)
5638c2ecf20Sopenharmony_ci		seq_puts(m, ",noquotadf");
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci#ifdef CONFIG_CEPH_FS_POSIX_ACL
5668c2ecf20Sopenharmony_ci	if (root->d_sb->s_flags & SB_POSIXACL)
5678c2ecf20Sopenharmony_ci		seq_puts(m, ",acl");
5688c2ecf20Sopenharmony_ci	else
5698c2ecf20Sopenharmony_ci		seq_puts(m, ",noacl");
5708c2ecf20Sopenharmony_ci#endif
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	if ((fsopt->flags & CEPH_MOUNT_OPT_NOCOPYFROM) == 0)
5738c2ecf20Sopenharmony_ci		seq_puts(m, ",copyfrom");
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	if (fsopt->mds_namespace)
5768c2ecf20Sopenharmony_ci		seq_show_option(m, "mds_namespace", fsopt->mds_namespace);
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	if (fsopt->flags & CEPH_MOUNT_OPT_CLEANRECOVER)
5798c2ecf20Sopenharmony_ci		seq_show_option(m, "recover_session", "clean");
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	if (fsopt->flags & CEPH_MOUNT_OPT_ASYNC_DIROPS)
5828c2ecf20Sopenharmony_ci		seq_puts(m, ",nowsync");
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	if (fsopt->wsize != CEPH_MAX_WRITE_SIZE)
5858c2ecf20Sopenharmony_ci		seq_printf(m, ",wsize=%u", fsopt->wsize);
5868c2ecf20Sopenharmony_ci	if (fsopt->rsize != CEPH_MAX_READ_SIZE)
5878c2ecf20Sopenharmony_ci		seq_printf(m, ",rsize=%u", fsopt->rsize);
5888c2ecf20Sopenharmony_ci	if (fsopt->rasize != CEPH_RASIZE_DEFAULT)
5898c2ecf20Sopenharmony_ci		seq_printf(m, ",rasize=%u", fsopt->rasize);
5908c2ecf20Sopenharmony_ci	if (fsopt->congestion_kb != default_congestion_kb())
5918c2ecf20Sopenharmony_ci		seq_printf(m, ",write_congestion_kb=%u", fsopt->congestion_kb);
5928c2ecf20Sopenharmony_ci	if (fsopt->caps_max)
5938c2ecf20Sopenharmony_ci		seq_printf(m, ",caps_max=%d", fsopt->caps_max);
5948c2ecf20Sopenharmony_ci	if (fsopt->caps_wanted_delay_min != CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT)
5958c2ecf20Sopenharmony_ci		seq_printf(m, ",caps_wanted_delay_min=%u",
5968c2ecf20Sopenharmony_ci			 fsopt->caps_wanted_delay_min);
5978c2ecf20Sopenharmony_ci	if (fsopt->caps_wanted_delay_max != CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT)
5988c2ecf20Sopenharmony_ci		seq_printf(m, ",caps_wanted_delay_max=%u",
5998c2ecf20Sopenharmony_ci			   fsopt->caps_wanted_delay_max);
6008c2ecf20Sopenharmony_ci	if (fsopt->max_readdir != CEPH_MAX_READDIR_DEFAULT)
6018c2ecf20Sopenharmony_ci		seq_printf(m, ",readdir_max_entries=%u", fsopt->max_readdir);
6028c2ecf20Sopenharmony_ci	if (fsopt->max_readdir_bytes != CEPH_MAX_READDIR_BYTES_DEFAULT)
6038c2ecf20Sopenharmony_ci		seq_printf(m, ",readdir_max_bytes=%u", fsopt->max_readdir_bytes);
6048c2ecf20Sopenharmony_ci	if (strcmp(fsopt->snapdir_name, CEPH_SNAPDIRNAME_DEFAULT))
6058c2ecf20Sopenharmony_ci		seq_show_option(m, "snapdirname", fsopt->snapdir_name);
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	return 0;
6088c2ecf20Sopenharmony_ci}
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci/*
6118c2ecf20Sopenharmony_ci * handle any mon messages the standard library doesn't understand.
6128c2ecf20Sopenharmony_ci * return error if we don't either.
6138c2ecf20Sopenharmony_ci */
6148c2ecf20Sopenharmony_cistatic int extra_mon_dispatch(struct ceph_client *client, struct ceph_msg *msg)
6158c2ecf20Sopenharmony_ci{
6168c2ecf20Sopenharmony_ci	struct ceph_fs_client *fsc = client->private;
6178c2ecf20Sopenharmony_ci	int type = le16_to_cpu(msg->hdr.type);
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	switch (type) {
6208c2ecf20Sopenharmony_ci	case CEPH_MSG_MDS_MAP:
6218c2ecf20Sopenharmony_ci		ceph_mdsc_handle_mdsmap(fsc->mdsc, msg);
6228c2ecf20Sopenharmony_ci		return 0;
6238c2ecf20Sopenharmony_ci	case CEPH_MSG_FS_MAP_USER:
6248c2ecf20Sopenharmony_ci		ceph_mdsc_handle_fsmap(fsc->mdsc, msg);
6258c2ecf20Sopenharmony_ci		return 0;
6268c2ecf20Sopenharmony_ci	default:
6278c2ecf20Sopenharmony_ci		return -1;
6288c2ecf20Sopenharmony_ci	}
6298c2ecf20Sopenharmony_ci}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci/*
6328c2ecf20Sopenharmony_ci * create a new fs client
6338c2ecf20Sopenharmony_ci *
6348c2ecf20Sopenharmony_ci * Success or not, this function consumes @fsopt and @opt.
6358c2ecf20Sopenharmony_ci */
6368c2ecf20Sopenharmony_cistatic struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt,
6378c2ecf20Sopenharmony_ci					struct ceph_options *opt)
6388c2ecf20Sopenharmony_ci{
6398c2ecf20Sopenharmony_ci	struct ceph_fs_client *fsc;
6408c2ecf20Sopenharmony_ci	int err;
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	fsc = kzalloc(sizeof(*fsc), GFP_KERNEL);
6438c2ecf20Sopenharmony_ci	if (!fsc) {
6448c2ecf20Sopenharmony_ci		err = -ENOMEM;
6458c2ecf20Sopenharmony_ci		goto fail;
6468c2ecf20Sopenharmony_ci	}
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	fsc->client = ceph_create_client(opt, fsc);
6498c2ecf20Sopenharmony_ci	if (IS_ERR(fsc->client)) {
6508c2ecf20Sopenharmony_ci		err = PTR_ERR(fsc->client);
6518c2ecf20Sopenharmony_ci		goto fail;
6528c2ecf20Sopenharmony_ci	}
6538c2ecf20Sopenharmony_ci	opt = NULL; /* fsc->client now owns this */
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	fsc->client->extra_mon_dispatch = extra_mon_dispatch;
6568c2ecf20Sopenharmony_ci	ceph_set_opt(fsc->client, ABORT_ON_FULL);
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	if (!fsopt->mds_namespace) {
6598c2ecf20Sopenharmony_ci		ceph_monc_want_map(&fsc->client->monc, CEPH_SUB_MDSMAP,
6608c2ecf20Sopenharmony_ci				   0, true);
6618c2ecf20Sopenharmony_ci	} else {
6628c2ecf20Sopenharmony_ci		ceph_monc_want_map(&fsc->client->monc, CEPH_SUB_FSMAP,
6638c2ecf20Sopenharmony_ci				   0, false);
6648c2ecf20Sopenharmony_ci	}
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	fsc->mount_options = fsopt;
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	fsc->sb = NULL;
6698c2ecf20Sopenharmony_ci	fsc->mount_state = CEPH_MOUNT_MOUNTING;
6708c2ecf20Sopenharmony_ci	fsc->filp_gen = 1;
6718c2ecf20Sopenharmony_ci	fsc->have_copy_from2 = true;
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	atomic_long_set(&fsc->writeback_count, 0);
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	err = -ENOMEM;
6768c2ecf20Sopenharmony_ci	/*
6778c2ecf20Sopenharmony_ci	 * The number of concurrent works can be high but they don't need
6788c2ecf20Sopenharmony_ci	 * to be processed in parallel, limit concurrency.
6798c2ecf20Sopenharmony_ci	 */
6808c2ecf20Sopenharmony_ci	fsc->inode_wq = alloc_workqueue("ceph-inode", WQ_UNBOUND, 0);
6818c2ecf20Sopenharmony_ci	if (!fsc->inode_wq)
6828c2ecf20Sopenharmony_ci		goto fail_client;
6838c2ecf20Sopenharmony_ci	fsc->cap_wq = alloc_workqueue("ceph-cap", 0, 1);
6848c2ecf20Sopenharmony_ci	if (!fsc->cap_wq)
6858c2ecf20Sopenharmony_ci		goto fail_inode_wq;
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	spin_lock(&ceph_fsc_lock);
6888c2ecf20Sopenharmony_ci	list_add_tail(&fsc->metric_wakeup, &ceph_fsc_list);
6898c2ecf20Sopenharmony_ci	spin_unlock(&ceph_fsc_lock);
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	return fsc;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_cifail_inode_wq:
6948c2ecf20Sopenharmony_ci	destroy_workqueue(fsc->inode_wq);
6958c2ecf20Sopenharmony_cifail_client:
6968c2ecf20Sopenharmony_ci	ceph_destroy_client(fsc->client);
6978c2ecf20Sopenharmony_cifail:
6988c2ecf20Sopenharmony_ci	kfree(fsc);
6998c2ecf20Sopenharmony_ci	if (opt)
7008c2ecf20Sopenharmony_ci		ceph_destroy_options(opt);
7018c2ecf20Sopenharmony_ci	destroy_mount_options(fsopt);
7028c2ecf20Sopenharmony_ci	return ERR_PTR(err);
7038c2ecf20Sopenharmony_ci}
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_cistatic void flush_fs_workqueues(struct ceph_fs_client *fsc)
7068c2ecf20Sopenharmony_ci{
7078c2ecf20Sopenharmony_ci	flush_workqueue(fsc->inode_wq);
7088c2ecf20Sopenharmony_ci	flush_workqueue(fsc->cap_wq);
7098c2ecf20Sopenharmony_ci}
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_cistatic void destroy_fs_client(struct ceph_fs_client *fsc)
7128c2ecf20Sopenharmony_ci{
7138c2ecf20Sopenharmony_ci	dout("destroy_fs_client %p\n", fsc);
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	spin_lock(&ceph_fsc_lock);
7168c2ecf20Sopenharmony_ci	list_del(&fsc->metric_wakeup);
7178c2ecf20Sopenharmony_ci	spin_unlock(&ceph_fsc_lock);
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	ceph_mdsc_destroy(fsc);
7208c2ecf20Sopenharmony_ci	destroy_workqueue(fsc->inode_wq);
7218c2ecf20Sopenharmony_ci	destroy_workqueue(fsc->cap_wq);
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	destroy_mount_options(fsc->mount_options);
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	ceph_destroy_client(fsc->client);
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	kfree(fsc);
7288c2ecf20Sopenharmony_ci	dout("destroy_fs_client %p done\n", fsc);
7298c2ecf20Sopenharmony_ci}
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci/*
7328c2ecf20Sopenharmony_ci * caches
7338c2ecf20Sopenharmony_ci */
7348c2ecf20Sopenharmony_cistruct kmem_cache *ceph_inode_cachep;
7358c2ecf20Sopenharmony_cistruct kmem_cache *ceph_cap_cachep;
7368c2ecf20Sopenharmony_cistruct kmem_cache *ceph_cap_flush_cachep;
7378c2ecf20Sopenharmony_cistruct kmem_cache *ceph_dentry_cachep;
7388c2ecf20Sopenharmony_cistruct kmem_cache *ceph_file_cachep;
7398c2ecf20Sopenharmony_cistruct kmem_cache *ceph_dir_file_cachep;
7408c2ecf20Sopenharmony_cistruct kmem_cache *ceph_mds_request_cachep;
7418c2ecf20Sopenharmony_cimempool_t *ceph_wb_pagevec_pool;
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_cistatic void ceph_inode_init_once(void *foo)
7448c2ecf20Sopenharmony_ci{
7458c2ecf20Sopenharmony_ci	struct ceph_inode_info *ci = foo;
7468c2ecf20Sopenharmony_ci	inode_init_once(&ci->vfs_inode);
7478c2ecf20Sopenharmony_ci}
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_cistatic int __init init_caches(void)
7508c2ecf20Sopenharmony_ci{
7518c2ecf20Sopenharmony_ci	int error = -ENOMEM;
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	ceph_inode_cachep = kmem_cache_create("ceph_inode_info",
7548c2ecf20Sopenharmony_ci				      sizeof(struct ceph_inode_info),
7558c2ecf20Sopenharmony_ci				      __alignof__(struct ceph_inode_info),
7568c2ecf20Sopenharmony_ci				      SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD|
7578c2ecf20Sopenharmony_ci				      SLAB_ACCOUNT, ceph_inode_init_once);
7588c2ecf20Sopenharmony_ci	if (!ceph_inode_cachep)
7598c2ecf20Sopenharmony_ci		return -ENOMEM;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	ceph_cap_cachep = KMEM_CACHE(ceph_cap, SLAB_MEM_SPREAD);
7628c2ecf20Sopenharmony_ci	if (!ceph_cap_cachep)
7638c2ecf20Sopenharmony_ci		goto bad_cap;
7648c2ecf20Sopenharmony_ci	ceph_cap_flush_cachep = KMEM_CACHE(ceph_cap_flush,
7658c2ecf20Sopenharmony_ci					   SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
7668c2ecf20Sopenharmony_ci	if (!ceph_cap_flush_cachep)
7678c2ecf20Sopenharmony_ci		goto bad_cap_flush;
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	ceph_dentry_cachep = KMEM_CACHE(ceph_dentry_info,
7708c2ecf20Sopenharmony_ci					SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
7718c2ecf20Sopenharmony_ci	if (!ceph_dentry_cachep)
7728c2ecf20Sopenharmony_ci		goto bad_dentry;
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	ceph_file_cachep = KMEM_CACHE(ceph_file_info, SLAB_MEM_SPREAD);
7758c2ecf20Sopenharmony_ci	if (!ceph_file_cachep)
7768c2ecf20Sopenharmony_ci		goto bad_file;
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	ceph_dir_file_cachep = KMEM_CACHE(ceph_dir_file_info, SLAB_MEM_SPREAD);
7798c2ecf20Sopenharmony_ci	if (!ceph_dir_file_cachep)
7808c2ecf20Sopenharmony_ci		goto bad_dir_file;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	ceph_mds_request_cachep = KMEM_CACHE(ceph_mds_request, SLAB_MEM_SPREAD);
7838c2ecf20Sopenharmony_ci	if (!ceph_mds_request_cachep)
7848c2ecf20Sopenharmony_ci		goto bad_mds_req;
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	ceph_wb_pagevec_pool = mempool_create_kmalloc_pool(10, CEPH_MAX_WRITE_SIZE >> PAGE_SHIFT);
7878c2ecf20Sopenharmony_ci	if (!ceph_wb_pagevec_pool)
7888c2ecf20Sopenharmony_ci		goto bad_pagevec_pool;
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	error = ceph_fscache_register();
7918c2ecf20Sopenharmony_ci	if (error)
7928c2ecf20Sopenharmony_ci		goto bad_fscache;
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	return 0;
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_cibad_fscache:
7978c2ecf20Sopenharmony_ci	kmem_cache_destroy(ceph_mds_request_cachep);
7988c2ecf20Sopenharmony_cibad_pagevec_pool:
7998c2ecf20Sopenharmony_ci	mempool_destroy(ceph_wb_pagevec_pool);
8008c2ecf20Sopenharmony_cibad_mds_req:
8018c2ecf20Sopenharmony_ci	kmem_cache_destroy(ceph_dir_file_cachep);
8028c2ecf20Sopenharmony_cibad_dir_file:
8038c2ecf20Sopenharmony_ci	kmem_cache_destroy(ceph_file_cachep);
8048c2ecf20Sopenharmony_cibad_file:
8058c2ecf20Sopenharmony_ci	kmem_cache_destroy(ceph_dentry_cachep);
8068c2ecf20Sopenharmony_cibad_dentry:
8078c2ecf20Sopenharmony_ci	kmem_cache_destroy(ceph_cap_flush_cachep);
8088c2ecf20Sopenharmony_cibad_cap_flush:
8098c2ecf20Sopenharmony_ci	kmem_cache_destroy(ceph_cap_cachep);
8108c2ecf20Sopenharmony_cibad_cap:
8118c2ecf20Sopenharmony_ci	kmem_cache_destroy(ceph_inode_cachep);
8128c2ecf20Sopenharmony_ci	return error;
8138c2ecf20Sopenharmony_ci}
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_cistatic void destroy_caches(void)
8168c2ecf20Sopenharmony_ci{
8178c2ecf20Sopenharmony_ci	/*
8188c2ecf20Sopenharmony_ci	 * Make sure all delayed rcu free inodes are flushed before we
8198c2ecf20Sopenharmony_ci	 * destroy cache.
8208c2ecf20Sopenharmony_ci	 */
8218c2ecf20Sopenharmony_ci	rcu_barrier();
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	kmem_cache_destroy(ceph_inode_cachep);
8248c2ecf20Sopenharmony_ci	kmem_cache_destroy(ceph_cap_cachep);
8258c2ecf20Sopenharmony_ci	kmem_cache_destroy(ceph_cap_flush_cachep);
8268c2ecf20Sopenharmony_ci	kmem_cache_destroy(ceph_dentry_cachep);
8278c2ecf20Sopenharmony_ci	kmem_cache_destroy(ceph_file_cachep);
8288c2ecf20Sopenharmony_ci	kmem_cache_destroy(ceph_dir_file_cachep);
8298c2ecf20Sopenharmony_ci	kmem_cache_destroy(ceph_mds_request_cachep);
8308c2ecf20Sopenharmony_ci	mempool_destroy(ceph_wb_pagevec_pool);
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	ceph_fscache_unregister();
8338c2ecf20Sopenharmony_ci}
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci/*
8368c2ecf20Sopenharmony_ci * ceph_umount_begin - initiate forced umount.  Tear down the
8378c2ecf20Sopenharmony_ci * mount, skipping steps that may hang while waiting for server(s).
8388c2ecf20Sopenharmony_ci */
8398c2ecf20Sopenharmony_cistatic void ceph_umount_begin(struct super_block *sb)
8408c2ecf20Sopenharmony_ci{
8418c2ecf20Sopenharmony_ci	struct ceph_fs_client *fsc = ceph_sb_to_client(sb);
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	dout("ceph_umount_begin - starting forced umount\n");
8448c2ecf20Sopenharmony_ci	if (!fsc)
8458c2ecf20Sopenharmony_ci		return;
8468c2ecf20Sopenharmony_ci	fsc->mount_state = CEPH_MOUNT_SHUTDOWN;
8478c2ecf20Sopenharmony_ci	ceph_osdc_abort_requests(&fsc->client->osdc, -EIO);
8488c2ecf20Sopenharmony_ci	ceph_mdsc_force_umount(fsc->mdsc);
8498c2ecf20Sopenharmony_ci	fsc->filp_gen++; // invalidate open files
8508c2ecf20Sopenharmony_ci}
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_cistatic const struct super_operations ceph_super_ops = {
8538c2ecf20Sopenharmony_ci	.alloc_inode	= ceph_alloc_inode,
8548c2ecf20Sopenharmony_ci	.free_inode	= ceph_free_inode,
8558c2ecf20Sopenharmony_ci	.write_inode    = ceph_write_inode,
8568c2ecf20Sopenharmony_ci	.drop_inode	= generic_delete_inode,
8578c2ecf20Sopenharmony_ci	.evict_inode	= ceph_evict_inode,
8588c2ecf20Sopenharmony_ci	.sync_fs        = ceph_sync_fs,
8598c2ecf20Sopenharmony_ci	.put_super	= ceph_put_super,
8608c2ecf20Sopenharmony_ci	.show_options   = ceph_show_options,
8618c2ecf20Sopenharmony_ci	.statfs		= ceph_statfs,
8628c2ecf20Sopenharmony_ci	.umount_begin   = ceph_umount_begin,
8638c2ecf20Sopenharmony_ci};
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci/*
8668c2ecf20Sopenharmony_ci * Bootstrap mount by opening the root directory.  Note the mount
8678c2ecf20Sopenharmony_ci * @started time from caller, and time out if this takes too long.
8688c2ecf20Sopenharmony_ci */
8698c2ecf20Sopenharmony_cistatic struct dentry *open_root_dentry(struct ceph_fs_client *fsc,
8708c2ecf20Sopenharmony_ci				       const char *path,
8718c2ecf20Sopenharmony_ci				       unsigned long started)
8728c2ecf20Sopenharmony_ci{
8738c2ecf20Sopenharmony_ci	struct ceph_mds_client *mdsc = fsc->mdsc;
8748c2ecf20Sopenharmony_ci	struct ceph_mds_request *req = NULL;
8758c2ecf20Sopenharmony_ci	int err;
8768c2ecf20Sopenharmony_ci	struct dentry *root;
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	/* open dir */
8798c2ecf20Sopenharmony_ci	dout("open_root_inode opening '%s'\n", path);
8808c2ecf20Sopenharmony_ci	req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_GETATTR, USE_ANY_MDS);
8818c2ecf20Sopenharmony_ci	if (IS_ERR(req))
8828c2ecf20Sopenharmony_ci		return ERR_CAST(req);
8838c2ecf20Sopenharmony_ci	req->r_path1 = kstrdup(path, GFP_NOFS);
8848c2ecf20Sopenharmony_ci	if (!req->r_path1) {
8858c2ecf20Sopenharmony_ci		root = ERR_PTR(-ENOMEM);
8868c2ecf20Sopenharmony_ci		goto out;
8878c2ecf20Sopenharmony_ci	}
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	req->r_ino1.ino = CEPH_INO_ROOT;
8908c2ecf20Sopenharmony_ci	req->r_ino1.snap = CEPH_NOSNAP;
8918c2ecf20Sopenharmony_ci	req->r_started = started;
8928c2ecf20Sopenharmony_ci	req->r_timeout = fsc->client->options->mount_timeout;
8938c2ecf20Sopenharmony_ci	req->r_args.getattr.mask = cpu_to_le32(CEPH_STAT_CAP_INODE);
8948c2ecf20Sopenharmony_ci	req->r_num_caps = 2;
8958c2ecf20Sopenharmony_ci	err = ceph_mdsc_do_request(mdsc, NULL, req);
8968c2ecf20Sopenharmony_ci	if (err == 0) {
8978c2ecf20Sopenharmony_ci		struct inode *inode = req->r_target_inode;
8988c2ecf20Sopenharmony_ci		req->r_target_inode = NULL;
8998c2ecf20Sopenharmony_ci		dout("open_root_inode success\n");
9008c2ecf20Sopenharmony_ci		root = d_make_root(inode);
9018c2ecf20Sopenharmony_ci		if (!root) {
9028c2ecf20Sopenharmony_ci			root = ERR_PTR(-ENOMEM);
9038c2ecf20Sopenharmony_ci			goto out;
9048c2ecf20Sopenharmony_ci		}
9058c2ecf20Sopenharmony_ci		dout("open_root_inode success, root dentry is %p\n", root);
9068c2ecf20Sopenharmony_ci	} else {
9078c2ecf20Sopenharmony_ci		root = ERR_PTR(err);
9088c2ecf20Sopenharmony_ci	}
9098c2ecf20Sopenharmony_ciout:
9108c2ecf20Sopenharmony_ci	ceph_mdsc_put_request(req);
9118c2ecf20Sopenharmony_ci	return root;
9128c2ecf20Sopenharmony_ci}
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci/*
9158c2ecf20Sopenharmony_ci * mount: join the ceph cluster, and open root directory.
9168c2ecf20Sopenharmony_ci */
9178c2ecf20Sopenharmony_cistatic struct dentry *ceph_real_mount(struct ceph_fs_client *fsc,
9188c2ecf20Sopenharmony_ci				      struct fs_context *fc)
9198c2ecf20Sopenharmony_ci{
9208c2ecf20Sopenharmony_ci	int err;
9218c2ecf20Sopenharmony_ci	unsigned long started = jiffies;  /* note the start time */
9228c2ecf20Sopenharmony_ci	struct dentry *root;
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	dout("mount start %p\n", fsc);
9258c2ecf20Sopenharmony_ci	mutex_lock(&fsc->client->mount_mutex);
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	if (!fsc->sb->s_root) {
9288c2ecf20Sopenharmony_ci		const char *path = fsc->mount_options->server_path ?
9298c2ecf20Sopenharmony_ci				     fsc->mount_options->server_path + 1 : "";
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci		err = __ceph_open_session(fsc->client, started);
9328c2ecf20Sopenharmony_ci		if (err < 0)
9338c2ecf20Sopenharmony_ci			goto out;
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci		/* setup fscache */
9368c2ecf20Sopenharmony_ci		if (fsc->mount_options->flags & CEPH_MOUNT_OPT_FSCACHE) {
9378c2ecf20Sopenharmony_ci			err = ceph_fscache_register_fs(fsc, fc);
9388c2ecf20Sopenharmony_ci			if (err < 0)
9398c2ecf20Sopenharmony_ci				goto out;
9408c2ecf20Sopenharmony_ci		}
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci		dout("mount opening path '%s'\n", path);
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci		ceph_fs_debugfs_init(fsc);
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci		root = open_root_dentry(fsc, path, started);
9478c2ecf20Sopenharmony_ci		if (IS_ERR(root)) {
9488c2ecf20Sopenharmony_ci			err = PTR_ERR(root);
9498c2ecf20Sopenharmony_ci			goto out;
9508c2ecf20Sopenharmony_ci		}
9518c2ecf20Sopenharmony_ci		fsc->sb->s_root = dget(root);
9528c2ecf20Sopenharmony_ci	} else {
9538c2ecf20Sopenharmony_ci		root = dget(fsc->sb->s_root);
9548c2ecf20Sopenharmony_ci	}
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci	fsc->mount_state = CEPH_MOUNT_MOUNTED;
9578c2ecf20Sopenharmony_ci	dout("mount success\n");
9588c2ecf20Sopenharmony_ci	mutex_unlock(&fsc->client->mount_mutex);
9598c2ecf20Sopenharmony_ci	return root;
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ciout:
9628c2ecf20Sopenharmony_ci	mutex_unlock(&fsc->client->mount_mutex);
9638c2ecf20Sopenharmony_ci	return ERR_PTR(err);
9648c2ecf20Sopenharmony_ci}
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_cistatic int ceph_set_super(struct super_block *s, struct fs_context *fc)
9678c2ecf20Sopenharmony_ci{
9688c2ecf20Sopenharmony_ci	struct ceph_fs_client *fsc = s->s_fs_info;
9698c2ecf20Sopenharmony_ci	int ret;
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci	dout("set_super %p\n", s);
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	s->s_maxbytes = MAX_LFS_FILESIZE;
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	s->s_xattr = ceph_xattr_handlers;
9768c2ecf20Sopenharmony_ci	fsc->sb = s;
9778c2ecf20Sopenharmony_ci	fsc->max_file_size = 1ULL << 40; /* temp value until we get mdsmap */
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	s->s_op = &ceph_super_ops;
9808c2ecf20Sopenharmony_ci	s->s_d_op = &ceph_dentry_ops;
9818c2ecf20Sopenharmony_ci	s->s_export_op = &ceph_export_ops;
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	s->s_time_gran = 1;
9848c2ecf20Sopenharmony_ci	s->s_time_min = 0;
9858c2ecf20Sopenharmony_ci	s->s_time_max = U32_MAX;
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci	ret = set_anon_super_fc(s, fc);
9888c2ecf20Sopenharmony_ci	if (ret != 0)
9898c2ecf20Sopenharmony_ci		fsc->sb = NULL;
9908c2ecf20Sopenharmony_ci	return ret;
9918c2ecf20Sopenharmony_ci}
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci/*
9948c2ecf20Sopenharmony_ci * share superblock if same fs AND options
9958c2ecf20Sopenharmony_ci */
9968c2ecf20Sopenharmony_cistatic int ceph_compare_super(struct super_block *sb, struct fs_context *fc)
9978c2ecf20Sopenharmony_ci{
9988c2ecf20Sopenharmony_ci	struct ceph_fs_client *new = fc->s_fs_info;
9998c2ecf20Sopenharmony_ci	struct ceph_mount_options *fsopt = new->mount_options;
10008c2ecf20Sopenharmony_ci	struct ceph_options *opt = new->client->options;
10018c2ecf20Sopenharmony_ci	struct ceph_fs_client *fsc = ceph_sb_to_client(sb);
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	dout("ceph_compare_super %p\n", sb);
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	if (compare_mount_options(fsopt, opt, fsc)) {
10068c2ecf20Sopenharmony_ci		dout("monitor(s)/mount options don't match\n");
10078c2ecf20Sopenharmony_ci		return 0;
10088c2ecf20Sopenharmony_ci	}
10098c2ecf20Sopenharmony_ci	if ((opt->flags & CEPH_OPT_FSID) &&
10108c2ecf20Sopenharmony_ci	    ceph_fsid_compare(&opt->fsid, &fsc->client->fsid)) {
10118c2ecf20Sopenharmony_ci		dout("fsid doesn't match\n");
10128c2ecf20Sopenharmony_ci		return 0;
10138c2ecf20Sopenharmony_ci	}
10148c2ecf20Sopenharmony_ci	if (fc->sb_flags != (sb->s_flags & ~SB_BORN)) {
10158c2ecf20Sopenharmony_ci		dout("flags differ\n");
10168c2ecf20Sopenharmony_ci		return 0;
10178c2ecf20Sopenharmony_ci	}
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	if (fsc->blocklisted && !ceph_test_mount_opt(fsc, CLEANRECOVER)) {
10208c2ecf20Sopenharmony_ci		dout("client is blocklisted (and CLEANRECOVER is not set)\n");
10218c2ecf20Sopenharmony_ci		return 0;
10228c2ecf20Sopenharmony_ci	}
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	if (fsc->mount_state == CEPH_MOUNT_SHUTDOWN) {
10258c2ecf20Sopenharmony_ci		dout("client has been forcibly unmounted\n");
10268c2ecf20Sopenharmony_ci		return 0;
10278c2ecf20Sopenharmony_ci	}
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	return 1;
10308c2ecf20Sopenharmony_ci}
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci/*
10338c2ecf20Sopenharmony_ci * construct our own bdi so we can control readahead, etc.
10348c2ecf20Sopenharmony_ci */
10358c2ecf20Sopenharmony_cistatic atomic_long_t bdi_seq = ATOMIC_LONG_INIT(0);
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_cistatic int ceph_setup_bdi(struct super_block *sb, struct ceph_fs_client *fsc)
10388c2ecf20Sopenharmony_ci{
10398c2ecf20Sopenharmony_ci	int err;
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	err = super_setup_bdi_name(sb, "ceph-%ld",
10428c2ecf20Sopenharmony_ci				   atomic_long_inc_return(&bdi_seq));
10438c2ecf20Sopenharmony_ci	if (err)
10448c2ecf20Sopenharmony_ci		return err;
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci	/* set ra_pages based on rasize mount option? */
10478c2ecf20Sopenharmony_ci	sb->s_bdi->ra_pages = fsc->mount_options->rasize >> PAGE_SHIFT;
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	/* set io_pages based on max osd read size */
10508c2ecf20Sopenharmony_ci	sb->s_bdi->io_pages = fsc->mount_options->rsize >> PAGE_SHIFT;
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	return 0;
10538c2ecf20Sopenharmony_ci}
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_cistatic int ceph_get_tree(struct fs_context *fc)
10568c2ecf20Sopenharmony_ci{
10578c2ecf20Sopenharmony_ci	struct ceph_parse_opts_ctx *pctx = fc->fs_private;
10588c2ecf20Sopenharmony_ci	struct super_block *sb;
10598c2ecf20Sopenharmony_ci	struct ceph_fs_client *fsc;
10608c2ecf20Sopenharmony_ci	struct dentry *res;
10618c2ecf20Sopenharmony_ci	int (*compare_super)(struct super_block *, struct fs_context *) =
10628c2ecf20Sopenharmony_ci		ceph_compare_super;
10638c2ecf20Sopenharmony_ci	int err;
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_ci	dout("ceph_get_tree\n");
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	if (!fc->source)
10688c2ecf20Sopenharmony_ci		return invalfc(fc, "No source");
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	/* create client (which we may/may not use) */
10718c2ecf20Sopenharmony_ci	fsc = create_fs_client(pctx->opts, pctx->copts);
10728c2ecf20Sopenharmony_ci	pctx->opts = NULL;
10738c2ecf20Sopenharmony_ci	pctx->copts = NULL;
10748c2ecf20Sopenharmony_ci	if (IS_ERR(fsc)) {
10758c2ecf20Sopenharmony_ci		err = PTR_ERR(fsc);
10768c2ecf20Sopenharmony_ci		goto out_final;
10778c2ecf20Sopenharmony_ci	}
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	err = ceph_mdsc_init(fsc);
10808c2ecf20Sopenharmony_ci	if (err < 0)
10818c2ecf20Sopenharmony_ci		goto out;
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	if (ceph_test_opt(fsc->client, NOSHARE))
10848c2ecf20Sopenharmony_ci		compare_super = NULL;
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci	fc->s_fs_info = fsc;
10878c2ecf20Sopenharmony_ci	sb = sget_fc(fc, compare_super, ceph_set_super);
10888c2ecf20Sopenharmony_ci	fc->s_fs_info = NULL;
10898c2ecf20Sopenharmony_ci	if (IS_ERR(sb)) {
10908c2ecf20Sopenharmony_ci		err = PTR_ERR(sb);
10918c2ecf20Sopenharmony_ci		goto out;
10928c2ecf20Sopenharmony_ci	}
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci	if (ceph_sb_to_client(sb) != fsc) {
10958c2ecf20Sopenharmony_ci		destroy_fs_client(fsc);
10968c2ecf20Sopenharmony_ci		fsc = ceph_sb_to_client(sb);
10978c2ecf20Sopenharmony_ci		dout("get_sb got existing client %p\n", fsc);
10988c2ecf20Sopenharmony_ci	} else {
10998c2ecf20Sopenharmony_ci		dout("get_sb using new client %p\n", fsc);
11008c2ecf20Sopenharmony_ci		err = ceph_setup_bdi(sb, fsc);
11018c2ecf20Sopenharmony_ci		if (err < 0)
11028c2ecf20Sopenharmony_ci			goto out_splat;
11038c2ecf20Sopenharmony_ci	}
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	res = ceph_real_mount(fsc, fc);
11068c2ecf20Sopenharmony_ci	if (IS_ERR(res)) {
11078c2ecf20Sopenharmony_ci		err = PTR_ERR(res);
11088c2ecf20Sopenharmony_ci		goto out_splat;
11098c2ecf20Sopenharmony_ci	}
11108c2ecf20Sopenharmony_ci	dout("root %p inode %p ino %llx.%llx\n", res,
11118c2ecf20Sopenharmony_ci	     d_inode(res), ceph_vinop(d_inode(res)));
11128c2ecf20Sopenharmony_ci	fc->root = fsc->sb->s_root;
11138c2ecf20Sopenharmony_ci	return 0;
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ciout_splat:
11168c2ecf20Sopenharmony_ci	if (!ceph_mdsmap_is_cluster_available(fsc->mdsc->mdsmap)) {
11178c2ecf20Sopenharmony_ci		pr_info("No mds server is up or the cluster is laggy\n");
11188c2ecf20Sopenharmony_ci		err = -EHOSTUNREACH;
11198c2ecf20Sopenharmony_ci	}
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci	ceph_mdsc_close_sessions(fsc->mdsc);
11228c2ecf20Sopenharmony_ci	deactivate_locked_super(sb);
11238c2ecf20Sopenharmony_ci	goto out_final;
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ciout:
11268c2ecf20Sopenharmony_ci	destroy_fs_client(fsc);
11278c2ecf20Sopenharmony_ciout_final:
11288c2ecf20Sopenharmony_ci	dout("ceph_get_tree fail %d\n", err);
11298c2ecf20Sopenharmony_ci	return err;
11308c2ecf20Sopenharmony_ci}
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_cistatic void ceph_free_fc(struct fs_context *fc)
11338c2ecf20Sopenharmony_ci{
11348c2ecf20Sopenharmony_ci	struct ceph_parse_opts_ctx *pctx = fc->fs_private;
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ci	if (pctx) {
11378c2ecf20Sopenharmony_ci		destroy_mount_options(pctx->opts);
11388c2ecf20Sopenharmony_ci		ceph_destroy_options(pctx->copts);
11398c2ecf20Sopenharmony_ci		kfree(pctx);
11408c2ecf20Sopenharmony_ci	}
11418c2ecf20Sopenharmony_ci}
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_cistatic int ceph_reconfigure_fc(struct fs_context *fc)
11448c2ecf20Sopenharmony_ci{
11458c2ecf20Sopenharmony_ci	struct ceph_parse_opts_ctx *pctx = fc->fs_private;
11468c2ecf20Sopenharmony_ci	struct ceph_mount_options *fsopt = pctx->opts;
11478c2ecf20Sopenharmony_ci	struct ceph_fs_client *fsc = ceph_sb_to_client(fc->root->d_sb);
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci	if (fsopt->flags & CEPH_MOUNT_OPT_ASYNC_DIROPS)
11508c2ecf20Sopenharmony_ci		ceph_set_mount_opt(fsc, ASYNC_DIROPS);
11518c2ecf20Sopenharmony_ci	else
11528c2ecf20Sopenharmony_ci		ceph_clear_mount_opt(fsc, ASYNC_DIROPS);
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	sync_filesystem(fc->root->d_sb);
11558c2ecf20Sopenharmony_ci	return 0;
11568c2ecf20Sopenharmony_ci}
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_cistatic const struct fs_context_operations ceph_context_ops = {
11598c2ecf20Sopenharmony_ci	.free		= ceph_free_fc,
11608c2ecf20Sopenharmony_ci	.parse_param	= ceph_parse_mount_param,
11618c2ecf20Sopenharmony_ci	.get_tree	= ceph_get_tree,
11628c2ecf20Sopenharmony_ci	.reconfigure	= ceph_reconfigure_fc,
11638c2ecf20Sopenharmony_ci};
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci/*
11668c2ecf20Sopenharmony_ci * Set up the filesystem mount context.
11678c2ecf20Sopenharmony_ci */
11688c2ecf20Sopenharmony_cistatic int ceph_init_fs_context(struct fs_context *fc)
11698c2ecf20Sopenharmony_ci{
11708c2ecf20Sopenharmony_ci	struct ceph_parse_opts_ctx *pctx;
11718c2ecf20Sopenharmony_ci	struct ceph_mount_options *fsopt;
11728c2ecf20Sopenharmony_ci
11738c2ecf20Sopenharmony_ci	pctx = kzalloc(sizeof(*pctx), GFP_KERNEL);
11748c2ecf20Sopenharmony_ci	if (!pctx)
11758c2ecf20Sopenharmony_ci		return -ENOMEM;
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci	pctx->copts = ceph_alloc_options();
11788c2ecf20Sopenharmony_ci	if (!pctx->copts)
11798c2ecf20Sopenharmony_ci		goto nomem;
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci	pctx->opts = kzalloc(sizeof(*pctx->opts), GFP_KERNEL);
11828c2ecf20Sopenharmony_ci	if (!pctx->opts)
11838c2ecf20Sopenharmony_ci		goto nomem;
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci	fsopt = pctx->opts;
11868c2ecf20Sopenharmony_ci	fsopt->flags = CEPH_MOUNT_OPT_DEFAULT;
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	fsopt->wsize = CEPH_MAX_WRITE_SIZE;
11898c2ecf20Sopenharmony_ci	fsopt->rsize = CEPH_MAX_READ_SIZE;
11908c2ecf20Sopenharmony_ci	fsopt->rasize = CEPH_RASIZE_DEFAULT;
11918c2ecf20Sopenharmony_ci	fsopt->snapdir_name = kstrdup(CEPH_SNAPDIRNAME_DEFAULT, GFP_KERNEL);
11928c2ecf20Sopenharmony_ci	if (!fsopt->snapdir_name)
11938c2ecf20Sopenharmony_ci		goto nomem;
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci	fsopt->caps_wanted_delay_min = CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT;
11968c2ecf20Sopenharmony_ci	fsopt->caps_wanted_delay_max = CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT;
11978c2ecf20Sopenharmony_ci	fsopt->max_readdir = CEPH_MAX_READDIR_DEFAULT;
11988c2ecf20Sopenharmony_ci	fsopt->max_readdir_bytes = CEPH_MAX_READDIR_BYTES_DEFAULT;
11998c2ecf20Sopenharmony_ci	fsopt->congestion_kb = default_congestion_kb();
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci#ifdef CONFIG_CEPH_FS_POSIX_ACL
12028c2ecf20Sopenharmony_ci	fc->sb_flags |= SB_POSIXACL;
12038c2ecf20Sopenharmony_ci#endif
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	fc->fs_private = pctx;
12068c2ecf20Sopenharmony_ci	fc->ops = &ceph_context_ops;
12078c2ecf20Sopenharmony_ci	return 0;
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_cinomem:
12108c2ecf20Sopenharmony_ci	destroy_mount_options(pctx->opts);
12118c2ecf20Sopenharmony_ci	ceph_destroy_options(pctx->copts);
12128c2ecf20Sopenharmony_ci	kfree(pctx);
12138c2ecf20Sopenharmony_ci	return -ENOMEM;
12148c2ecf20Sopenharmony_ci}
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_cistatic void ceph_kill_sb(struct super_block *s)
12178c2ecf20Sopenharmony_ci{
12188c2ecf20Sopenharmony_ci	struct ceph_fs_client *fsc = ceph_sb_to_client(s);
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_ci	dout("kill_sb %p\n", s);
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_ci	ceph_mdsc_pre_umount(fsc->mdsc);
12238c2ecf20Sopenharmony_ci	flush_fs_workqueues(fsc);
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci	/*
12268c2ecf20Sopenharmony_ci	 * Though the kill_anon_super() will finally trigger the
12278c2ecf20Sopenharmony_ci	 * sync_filesystem() anyway, we still need to do it here
12288c2ecf20Sopenharmony_ci	 * and then bump the stage of shutdown to stop the work
12298c2ecf20Sopenharmony_ci	 * queue as earlier as possible.
12308c2ecf20Sopenharmony_ci	 */
12318c2ecf20Sopenharmony_ci	sync_filesystem(s);
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci	fsc->mdsc->stopping = CEPH_MDSC_STOPPING_FLUSHED;
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci	kill_anon_super(s);
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	fsc->client->extra_mon_dispatch = NULL;
12388c2ecf20Sopenharmony_ci	ceph_fs_debugfs_cleanup(fsc);
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci	ceph_fscache_unregister_fs(fsc);
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci	destroy_fs_client(fsc);
12438c2ecf20Sopenharmony_ci}
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_cistatic struct file_system_type ceph_fs_type = {
12468c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
12478c2ecf20Sopenharmony_ci	.name		= "ceph",
12488c2ecf20Sopenharmony_ci	.init_fs_context = ceph_init_fs_context,
12498c2ecf20Sopenharmony_ci	.kill_sb	= ceph_kill_sb,
12508c2ecf20Sopenharmony_ci	.fs_flags	= FS_RENAME_DOES_D_MOVE,
12518c2ecf20Sopenharmony_ci};
12528c2ecf20Sopenharmony_ciMODULE_ALIAS_FS("ceph");
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ciint ceph_force_reconnect(struct super_block *sb)
12558c2ecf20Sopenharmony_ci{
12568c2ecf20Sopenharmony_ci	struct ceph_fs_client *fsc = ceph_sb_to_client(sb);
12578c2ecf20Sopenharmony_ci	int err = 0;
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci	ceph_umount_begin(sb);
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	/* Make sure all page caches get invalidated.
12628c2ecf20Sopenharmony_ci	 * see remove_session_caps_cb() */
12638c2ecf20Sopenharmony_ci	flush_workqueue(fsc->inode_wq);
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci	/* In case that we were blocklisted. This also reset
12668c2ecf20Sopenharmony_ci	 * all mon/osd connections */
12678c2ecf20Sopenharmony_ci	ceph_reset_client_addr(fsc->client);
12688c2ecf20Sopenharmony_ci
12698c2ecf20Sopenharmony_ci	ceph_osdc_clear_abort_err(&fsc->client->osdc);
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci	fsc->blocklisted = false;
12728c2ecf20Sopenharmony_ci	fsc->mount_state = CEPH_MOUNT_MOUNTED;
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci	if (sb->s_root) {
12758c2ecf20Sopenharmony_ci		err = __ceph_do_getattr(d_inode(sb->s_root), NULL,
12768c2ecf20Sopenharmony_ci					CEPH_STAT_CAP_INODE, true);
12778c2ecf20Sopenharmony_ci	}
12788c2ecf20Sopenharmony_ci	return err;
12798c2ecf20Sopenharmony_ci}
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_cistatic int __init init_ceph(void)
12828c2ecf20Sopenharmony_ci{
12838c2ecf20Sopenharmony_ci	int ret = init_caches();
12848c2ecf20Sopenharmony_ci	if (ret)
12858c2ecf20Sopenharmony_ci		goto out;
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci	ceph_flock_init();
12888c2ecf20Sopenharmony_ci	ret = register_filesystem(&ceph_fs_type);
12898c2ecf20Sopenharmony_ci	if (ret)
12908c2ecf20Sopenharmony_ci		goto out_caches;
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_ci	pr_info("loaded (mds proto %d)\n", CEPH_MDSC_PROTOCOL);
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci	return 0;
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ciout_caches:
12978c2ecf20Sopenharmony_ci	destroy_caches();
12988c2ecf20Sopenharmony_ciout:
12998c2ecf20Sopenharmony_ci	return ret;
13008c2ecf20Sopenharmony_ci}
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_cistatic void __exit exit_ceph(void)
13038c2ecf20Sopenharmony_ci{
13048c2ecf20Sopenharmony_ci	dout("exit_ceph\n");
13058c2ecf20Sopenharmony_ci	unregister_filesystem(&ceph_fs_type);
13068c2ecf20Sopenharmony_ci	destroy_caches();
13078c2ecf20Sopenharmony_ci}
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_cistatic int param_set_metrics(const char *val, const struct kernel_param *kp)
13108c2ecf20Sopenharmony_ci{
13118c2ecf20Sopenharmony_ci	struct ceph_fs_client *fsc;
13128c2ecf20Sopenharmony_ci	int ret;
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	ret = param_set_bool(val, kp);
13158c2ecf20Sopenharmony_ci	if (ret) {
13168c2ecf20Sopenharmony_ci		pr_err("Failed to parse sending metrics switch value '%s'\n",
13178c2ecf20Sopenharmony_ci		       val);
13188c2ecf20Sopenharmony_ci		return ret;
13198c2ecf20Sopenharmony_ci	} else if (!disable_send_metrics) {
13208c2ecf20Sopenharmony_ci		// wake up all the mds clients
13218c2ecf20Sopenharmony_ci		spin_lock(&ceph_fsc_lock);
13228c2ecf20Sopenharmony_ci		list_for_each_entry(fsc, &ceph_fsc_list, metric_wakeup) {
13238c2ecf20Sopenharmony_ci			metric_schedule_delayed(&fsc->mdsc->metric);
13248c2ecf20Sopenharmony_ci		}
13258c2ecf20Sopenharmony_ci		spin_unlock(&ceph_fsc_lock);
13268c2ecf20Sopenharmony_ci	}
13278c2ecf20Sopenharmony_ci
13288c2ecf20Sopenharmony_ci	return 0;
13298c2ecf20Sopenharmony_ci}
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_cistatic const struct kernel_param_ops param_ops_metrics = {
13328c2ecf20Sopenharmony_ci	.set = param_set_metrics,
13338c2ecf20Sopenharmony_ci	.get = param_get_bool,
13348c2ecf20Sopenharmony_ci};
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_cibool disable_send_metrics = false;
13378c2ecf20Sopenharmony_cimodule_param_cb(disable_send_metrics, &param_ops_metrics, &disable_send_metrics, 0644);
13388c2ecf20Sopenharmony_ciMODULE_PARM_DESC(disable_send_metrics, "Enable sending perf metrics to ceph cluster (default: on)");
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_cimodule_init(init_ceph);
13418c2ecf20Sopenharmony_cimodule_exit(exit_ceph);
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_ciMODULE_AUTHOR("Sage Weil <sage@newdream.net>");
13448c2ecf20Sopenharmony_ciMODULE_AUTHOR("Yehuda Sadeh <yehuda@hq.newdream.net>");
13458c2ecf20Sopenharmony_ciMODULE_AUTHOR("Patience Warnick <patience@newdream.net>");
13468c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Ceph filesystem for Linux");
13478c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1348