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