162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/* AFS client file system
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) 2002,5 Red Hat, Inc. All Rights Reserved.
562306a36Sopenharmony_ci * Written by David Howells (dhowells@redhat.com)
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/module.h>
962306a36Sopenharmony_ci#include <linux/moduleparam.h>
1062306a36Sopenharmony_ci#include <linux/init.h>
1162306a36Sopenharmony_ci#include <linux/completion.h>
1262306a36Sopenharmony_ci#include <linux/sched.h>
1362306a36Sopenharmony_ci#include <linux/random.h>
1462306a36Sopenharmony_ci#include <linux/proc_fs.h>
1562306a36Sopenharmony_ci#define CREATE_TRACE_POINTS
1662306a36Sopenharmony_ci#include "internal.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ciMODULE_DESCRIPTION("AFS Client File System");
1962306a36Sopenharmony_ciMODULE_AUTHOR("Red Hat, Inc.");
2062306a36Sopenharmony_ciMODULE_LICENSE("GPL");
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ciunsigned afs_debug;
2362306a36Sopenharmony_cimodule_param_named(debug, afs_debug, uint, S_IWUSR | S_IRUGO);
2462306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "AFS debugging mask");
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic char *rootcell;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cimodule_param(rootcell, charp, 0);
2962306a36Sopenharmony_ciMODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list");
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistruct workqueue_struct *afs_wq;
3262306a36Sopenharmony_cistatic struct proc_dir_entry *afs_proc_symlink;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#if defined(CONFIG_ALPHA)
3562306a36Sopenharmony_ciconst char afs_init_sysname[] = "alpha_linux26";
3662306a36Sopenharmony_ci#elif defined(CONFIG_X86_64)
3762306a36Sopenharmony_ciconst char afs_init_sysname[] = "amd64_linux26";
3862306a36Sopenharmony_ci#elif defined(CONFIG_ARM)
3962306a36Sopenharmony_ciconst char afs_init_sysname[] = "arm_linux26";
4062306a36Sopenharmony_ci#elif defined(CONFIG_ARM64)
4162306a36Sopenharmony_ciconst char afs_init_sysname[] = "aarch64_linux26";
4262306a36Sopenharmony_ci#elif defined(CONFIG_X86_32)
4362306a36Sopenharmony_ciconst char afs_init_sysname[] = "i386_linux26";
4462306a36Sopenharmony_ci#elif defined(CONFIG_IA64)
4562306a36Sopenharmony_ciconst char afs_init_sysname[] = "ia64_linux26";
4662306a36Sopenharmony_ci#elif defined(CONFIG_PPC64)
4762306a36Sopenharmony_ciconst char afs_init_sysname[] = "ppc64_linux26";
4862306a36Sopenharmony_ci#elif defined(CONFIG_PPC32)
4962306a36Sopenharmony_ciconst char afs_init_sysname[] = "ppc_linux26";
5062306a36Sopenharmony_ci#elif defined(CONFIG_S390)
5162306a36Sopenharmony_ci#ifdef CONFIG_64BIT
5262306a36Sopenharmony_ciconst char afs_init_sysname[] = "s390x_linux26";
5362306a36Sopenharmony_ci#else
5462306a36Sopenharmony_ciconst char afs_init_sysname[] = "s390_linux26";
5562306a36Sopenharmony_ci#endif
5662306a36Sopenharmony_ci#elif defined(CONFIG_SPARC64)
5762306a36Sopenharmony_ciconst char afs_init_sysname[] = "sparc64_linux26";
5862306a36Sopenharmony_ci#elif defined(CONFIG_SPARC32)
5962306a36Sopenharmony_ciconst char afs_init_sysname[] = "sparc_linux26";
6062306a36Sopenharmony_ci#else
6162306a36Sopenharmony_ciconst char afs_init_sysname[] = "unknown_linux26";
6262306a36Sopenharmony_ci#endif
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci/*
6562306a36Sopenharmony_ci * Initialise an AFS network namespace record.
6662306a36Sopenharmony_ci */
6762306a36Sopenharmony_cistatic int __net_init afs_net_init(struct net *net_ns)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	struct afs_sysnames *sysnames;
7062306a36Sopenharmony_ci	struct afs_net *net = afs_net(net_ns);
7162306a36Sopenharmony_ci	int ret;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	net->net = net_ns;
7462306a36Sopenharmony_ci	net->live = true;
7562306a36Sopenharmony_ci	generate_random_uuid((unsigned char *)&net->uuid);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	INIT_WORK(&net->charge_preallocation_work, afs_charge_preallocation);
7862306a36Sopenharmony_ci	mutex_init(&net->socket_mutex);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	net->cells = RB_ROOT;
8162306a36Sopenharmony_ci	init_rwsem(&net->cells_lock);
8262306a36Sopenharmony_ci	INIT_WORK(&net->cells_manager, afs_manage_cells);
8362306a36Sopenharmony_ci	timer_setup(&net->cells_timer, afs_cells_timer, 0);
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	mutex_init(&net->cells_alias_lock);
8662306a36Sopenharmony_ci	mutex_init(&net->proc_cells_lock);
8762306a36Sopenharmony_ci	INIT_HLIST_HEAD(&net->proc_cells);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	seqlock_init(&net->fs_lock);
9062306a36Sopenharmony_ci	net->fs_servers = RB_ROOT;
9162306a36Sopenharmony_ci	INIT_LIST_HEAD(&net->fs_probe_fast);
9262306a36Sopenharmony_ci	INIT_LIST_HEAD(&net->fs_probe_slow);
9362306a36Sopenharmony_ci	INIT_HLIST_HEAD(&net->fs_proc);
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	INIT_HLIST_HEAD(&net->fs_addresses4);
9662306a36Sopenharmony_ci	INIT_HLIST_HEAD(&net->fs_addresses6);
9762306a36Sopenharmony_ci	seqlock_init(&net->fs_addr_lock);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	INIT_WORK(&net->fs_manager, afs_manage_servers);
10062306a36Sopenharmony_ci	timer_setup(&net->fs_timer, afs_servers_timer, 0);
10162306a36Sopenharmony_ci	INIT_WORK(&net->fs_prober, afs_fs_probe_dispatcher);
10262306a36Sopenharmony_ci	timer_setup(&net->fs_probe_timer, afs_fs_probe_timer, 0);
10362306a36Sopenharmony_ci	atomic_set(&net->servers_outstanding, 1);
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	ret = -ENOMEM;
10662306a36Sopenharmony_ci	sysnames = kzalloc(sizeof(*sysnames), GFP_KERNEL);
10762306a36Sopenharmony_ci	if (!sysnames)
10862306a36Sopenharmony_ci		goto error_sysnames;
10962306a36Sopenharmony_ci	sysnames->subs[0] = (char *)&afs_init_sysname;
11062306a36Sopenharmony_ci	sysnames->nr = 1;
11162306a36Sopenharmony_ci	refcount_set(&sysnames->usage, 1);
11262306a36Sopenharmony_ci	net->sysnames = sysnames;
11362306a36Sopenharmony_ci	rwlock_init(&net->sysnames_lock);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	/* Register the /proc stuff */
11662306a36Sopenharmony_ci	ret = afs_proc_init(net);
11762306a36Sopenharmony_ci	if (ret < 0)
11862306a36Sopenharmony_ci		goto error_proc;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	/* Initialise the cell DB */
12162306a36Sopenharmony_ci	ret = afs_cell_init(net, rootcell);
12262306a36Sopenharmony_ci	if (ret < 0)
12362306a36Sopenharmony_ci		goto error_cell_init;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	/* Create the RxRPC transport */
12662306a36Sopenharmony_ci	ret = afs_open_socket(net);
12762306a36Sopenharmony_ci	if (ret < 0)
12862306a36Sopenharmony_ci		goto error_open_socket;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	return 0;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cierror_open_socket:
13362306a36Sopenharmony_ci	net->live = false;
13462306a36Sopenharmony_ci	afs_fs_probe_cleanup(net);
13562306a36Sopenharmony_ci	afs_cell_purge(net);
13662306a36Sopenharmony_ci	afs_purge_servers(net);
13762306a36Sopenharmony_cierror_cell_init:
13862306a36Sopenharmony_ci	net->live = false;
13962306a36Sopenharmony_ci	afs_proc_cleanup(net);
14062306a36Sopenharmony_cierror_proc:
14162306a36Sopenharmony_ci	afs_put_sysnames(net->sysnames);
14262306a36Sopenharmony_cierror_sysnames:
14362306a36Sopenharmony_ci	net->live = false;
14462306a36Sopenharmony_ci	return ret;
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci/*
14862306a36Sopenharmony_ci * Clean up and destroy an AFS network namespace record.
14962306a36Sopenharmony_ci */
15062306a36Sopenharmony_cistatic void __net_exit afs_net_exit(struct net *net_ns)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	struct afs_net *net = afs_net(net_ns);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	net->live = false;
15562306a36Sopenharmony_ci	afs_fs_probe_cleanup(net);
15662306a36Sopenharmony_ci	afs_cell_purge(net);
15762306a36Sopenharmony_ci	afs_purge_servers(net);
15862306a36Sopenharmony_ci	afs_close_socket(net);
15962306a36Sopenharmony_ci	afs_proc_cleanup(net);
16062306a36Sopenharmony_ci	afs_put_sysnames(net->sysnames);
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistatic struct pernet_operations afs_net_ops = {
16462306a36Sopenharmony_ci	.init	= afs_net_init,
16562306a36Sopenharmony_ci	.exit	= afs_net_exit,
16662306a36Sopenharmony_ci	.id	= &afs_net_id,
16762306a36Sopenharmony_ci	.size	= sizeof(struct afs_net),
16862306a36Sopenharmony_ci};
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci/*
17162306a36Sopenharmony_ci * initialise the AFS client FS module
17262306a36Sopenharmony_ci */
17362306a36Sopenharmony_cistatic int __init afs_init(void)
17462306a36Sopenharmony_ci{
17562306a36Sopenharmony_ci	int ret = -ENOMEM;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 registering.\n");
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	afs_wq = alloc_workqueue("afs", 0, 0);
18062306a36Sopenharmony_ci	if (!afs_wq)
18162306a36Sopenharmony_ci		goto error_afs_wq;
18262306a36Sopenharmony_ci	afs_async_calls = alloc_workqueue("kafsd", WQ_MEM_RECLAIM, 0);
18362306a36Sopenharmony_ci	if (!afs_async_calls)
18462306a36Sopenharmony_ci		goto error_async;
18562306a36Sopenharmony_ci	afs_lock_manager = alloc_workqueue("kafs_lockd", WQ_MEM_RECLAIM, 0);
18662306a36Sopenharmony_ci	if (!afs_lock_manager)
18762306a36Sopenharmony_ci		goto error_lockmgr;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	ret = register_pernet_device(&afs_net_ops);
19062306a36Sopenharmony_ci	if (ret < 0)
19162306a36Sopenharmony_ci		goto error_net;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	/* register the filesystems */
19462306a36Sopenharmony_ci	ret = afs_fs_init();
19562306a36Sopenharmony_ci	if (ret < 0)
19662306a36Sopenharmony_ci		goto error_fs;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	afs_proc_symlink = proc_symlink("fs/afs", NULL, "../self/net/afs");
19962306a36Sopenharmony_ci	if (!afs_proc_symlink) {
20062306a36Sopenharmony_ci		ret = -ENOMEM;
20162306a36Sopenharmony_ci		goto error_proc;
20262306a36Sopenharmony_ci	}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	return ret;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_cierror_proc:
20762306a36Sopenharmony_ci	afs_fs_exit();
20862306a36Sopenharmony_cierror_fs:
20962306a36Sopenharmony_ci	unregister_pernet_device(&afs_net_ops);
21062306a36Sopenharmony_cierror_net:
21162306a36Sopenharmony_ci	destroy_workqueue(afs_lock_manager);
21262306a36Sopenharmony_cierror_lockmgr:
21362306a36Sopenharmony_ci	destroy_workqueue(afs_async_calls);
21462306a36Sopenharmony_cierror_async:
21562306a36Sopenharmony_ci	destroy_workqueue(afs_wq);
21662306a36Sopenharmony_cierror_afs_wq:
21762306a36Sopenharmony_ci	rcu_barrier();
21862306a36Sopenharmony_ci	printk(KERN_ERR "kAFS: failed to register: %d\n", ret);
21962306a36Sopenharmony_ci	return ret;
22062306a36Sopenharmony_ci}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci/* XXX late_initcall is kludgy, but the only alternative seems to create
22362306a36Sopenharmony_ci * a transport upon the first mount, which is worse. Or is it?
22462306a36Sopenharmony_ci */
22562306a36Sopenharmony_cilate_initcall(afs_init);	/* must be called after net/ to create socket */
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci/*
22862306a36Sopenharmony_ci * clean up on module removal
22962306a36Sopenharmony_ci */
23062306a36Sopenharmony_cistatic void __exit afs_exit(void)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 unregistering.\n");
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	proc_remove(afs_proc_symlink);
23562306a36Sopenharmony_ci	afs_fs_exit();
23662306a36Sopenharmony_ci	unregister_pernet_device(&afs_net_ops);
23762306a36Sopenharmony_ci	destroy_workqueue(afs_lock_manager);
23862306a36Sopenharmony_ci	destroy_workqueue(afs_async_calls);
23962306a36Sopenharmony_ci	destroy_workqueue(afs_wq);
24062306a36Sopenharmony_ci	afs_clean_up_permit_cache();
24162306a36Sopenharmony_ci	rcu_barrier();
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cimodule_exit(afs_exit);
245