12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2ec26815aSDavid Howells /* AFS client file system 31da177e4SLinus Torvalds * 49b3f26c9SDavid Howells * Copyright (C) 2002,5 Red Hat, Inc. All Rights Reserved. 51da177e4SLinus Torvalds * Written by David Howells (dhowells@redhat.com) 61da177e4SLinus Torvalds */ 71da177e4SLinus Torvalds 81da177e4SLinus Torvalds #include <linux/module.h> 91da177e4SLinus Torvalds #include <linux/moduleparam.h> 101da177e4SLinus Torvalds #include <linux/init.h> 111da177e4SLinus Torvalds #include <linux/completion.h> 12e8edc6e0SAlexey Dobriyan #include <linux/sched.h> 13e0661dfcSDavid Howells #include <linux/random.h> 145b86d4ffSDavid Howells #include <linux/proc_fs.h> 158e8d7f13SDavid Howells #define CREATE_TRACE_POINTS 161da177e4SLinus Torvalds #include "internal.h" 171da177e4SLinus Torvalds 181da177e4SLinus Torvalds MODULE_DESCRIPTION("AFS Client File System"); 191da177e4SLinus Torvalds MODULE_AUTHOR("Red Hat, Inc."); 201da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 211da177e4SLinus Torvalds 2208e0e7c8SDavid Howells unsigned afs_debug; 2308e0e7c8SDavid Howells module_param_named(debug, afs_debug, uint, S_IWUSR | S_IRUGO); 24424b00e2SPaul Bolle MODULE_PARM_DESC(debug, "AFS debugging mask"); 2508e0e7c8SDavid Howells 261da177e4SLinus Torvalds static char *rootcell; 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds module_param(rootcell, charp, 0); 291da177e4SLinus Torvalds MODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list"); 301da177e4SLinus Torvalds 310ad53eeeSTejun Heo struct workqueue_struct *afs_wq; 325b86d4ffSDavid Howells static struct proc_dir_entry *afs_proc_symlink; 33f044c884SDavid Howells 346f8880d8SDavid Howells #if defined(CONFIG_ALPHA) 356f8880d8SDavid Howells const char afs_init_sysname[] = "alpha_linux26"; 366f8880d8SDavid Howells #elif defined(CONFIG_X86_64) 376f8880d8SDavid Howells const char afs_init_sysname[] = "amd64_linux26"; 386f8880d8SDavid Howells #elif defined(CONFIG_ARM) 396f8880d8SDavid Howells const char afs_init_sysname[] = "arm_linux26"; 406f8880d8SDavid Howells #elif defined(CONFIG_ARM64) 416f8880d8SDavid Howells const char afs_init_sysname[] = "aarch64_linux26"; 426f8880d8SDavid Howells #elif defined(CONFIG_X86_32) 436f8880d8SDavid Howells const char afs_init_sysname[] = "i386_linux26"; 446f8880d8SDavid Howells #elif defined(CONFIG_PPC64) 456f8880d8SDavid Howells const char afs_init_sysname[] = "ppc64_linux26"; 466f8880d8SDavid Howells #elif defined(CONFIG_PPC32) 476f8880d8SDavid Howells const char afs_init_sysname[] = "ppc_linux26"; 486f8880d8SDavid Howells #elif defined(CONFIG_S390) 496f8880d8SDavid Howells #ifdef CONFIG_64BIT 506f8880d8SDavid Howells const char afs_init_sysname[] = "s390x_linux26"; 516f8880d8SDavid Howells #else 526f8880d8SDavid Howells const char afs_init_sysname[] = "s390_linux26"; 536f8880d8SDavid Howells #endif 546f8880d8SDavid Howells #elif defined(CONFIG_SPARC64) 556f8880d8SDavid Howells const char afs_init_sysname[] = "sparc64_linux26"; 566f8880d8SDavid Howells #elif defined(CONFIG_SPARC32) 576f8880d8SDavid Howells const char afs_init_sysname[] = "sparc_linux26"; 586f8880d8SDavid Howells #else 596f8880d8SDavid Howells const char afs_init_sysname[] = "unknown_linux26"; 606f8880d8SDavid Howells #endif 616f8880d8SDavid Howells 62f044c884SDavid Howells /* 63f044c884SDavid Howells * Initialise an AFS network namespace record. 64f044c884SDavid Howells */ 655b86d4ffSDavid Howells static int __net_init afs_net_init(struct net *net_ns) 66f044c884SDavid Howells { 676f8880d8SDavid Howells struct afs_sysnames *sysnames; 685b86d4ffSDavid Howells struct afs_net *net = afs_net(net_ns); 69f044c884SDavid Howells int ret; 70f044c884SDavid Howells 715b86d4ffSDavid Howells net->net = net_ns; 72f044c884SDavid Howells net->live = true; 73f044c884SDavid Howells generate_random_uuid((unsigned char *)&net->uuid); 74f044c884SDavid Howells 75f044c884SDavid Howells INIT_WORK(&net->charge_preallocation_work, afs_charge_preallocation); 76f044c884SDavid Howells mutex_init(&net->socket_mutex); 77989782dcSDavid Howells 78989782dcSDavid Howells net->cells = RB_ROOT; 7992e3cc91SDavid Howells init_rwsem(&net->cells_lock); 80989782dcSDavid Howells INIT_WORK(&net->cells_manager, afs_manage_cells); 81989782dcSDavid Howells timer_setup(&net->cells_timer, afs_cells_timer, 0); 82989782dcSDavid Howells 838a070a96SDavid Howells mutex_init(&net->cells_alias_lock); 840da0b7fdSDavid Howells mutex_init(&net->proc_cells_lock); 856b3944e4SDavid Howells INIT_HLIST_HEAD(&net->proc_cells); 86989782dcSDavid Howells 87d2ddc776SDavid Howells seqlock_init(&net->fs_lock); 88d2ddc776SDavid Howells net->fs_servers = RB_ROOT; 89f6cbb368SDavid Howells INIT_LIST_HEAD(&net->fs_probe_fast); 90f6cbb368SDavid Howells INIT_LIST_HEAD(&net->fs_probe_slow); 91d2ddc776SDavid Howells INIT_HLIST_HEAD(&net->fs_proc); 92d2ddc776SDavid Howells 93d2ddc776SDavid Howells INIT_HLIST_HEAD(&net->fs_addresses4); 94d2ddc776SDavid Howells INIT_HLIST_HEAD(&net->fs_addresses6); 95d2ddc776SDavid Howells seqlock_init(&net->fs_addr_lock); 96d2ddc776SDavid Howells 97d2ddc776SDavid Howells INIT_WORK(&net->fs_manager, afs_manage_servers); 98d2ddc776SDavid Howells timer_setup(&net->fs_timer, afs_servers_timer, 0); 99f6cbb368SDavid Howells INIT_WORK(&net->fs_prober, afs_fs_probe_dispatcher); 100f6cbb368SDavid Howells timer_setup(&net->fs_probe_timer, afs_fs_probe_timer, 0); 1015481fc6eSDavid Howells atomic_set(&net->servers_outstanding, 1); 102f044c884SDavid Howells 1036f8880d8SDavid Howells ret = -ENOMEM; 1046f8880d8SDavid Howells sysnames = kzalloc(sizeof(*sysnames), GFP_KERNEL); 1056f8880d8SDavid Howells if (!sysnames) 1066f8880d8SDavid Howells goto error_sysnames; 1076f8880d8SDavid Howells sysnames->subs[0] = (char *)&afs_init_sysname; 1086f8880d8SDavid Howells sysnames->nr = 1; 1096f8880d8SDavid Howells refcount_set(&sysnames->usage, 1); 1106f8880d8SDavid Howells net->sysnames = sysnames; 1116f8880d8SDavid Howells rwlock_init(&net->sysnames_lock); 1126f8880d8SDavid Howells 113f044c884SDavid Howells /* Register the /proc stuff */ 114f044c884SDavid Howells ret = afs_proc_init(net); 115f044c884SDavid Howells if (ret < 0) 116f044c884SDavid Howells goto error_proc; 117f044c884SDavid Howells 118f044c884SDavid Howells /* Initialise the cell DB */ 119f044c884SDavid Howells ret = afs_cell_init(net, rootcell); 120f044c884SDavid Howells if (ret < 0) 121f044c884SDavid Howells goto error_cell_init; 122f044c884SDavid Howells 123f044c884SDavid Howells /* Create the RxRPC transport */ 124f044c884SDavid Howells ret = afs_open_socket(net); 125f044c884SDavid Howells if (ret < 0) 126f044c884SDavid Howells goto error_open_socket; 127f044c884SDavid Howells 128f044c884SDavid Howells return 0; 129f044c884SDavid Howells 130f044c884SDavid Howells error_open_socket: 131989782dcSDavid Howells net->live = false; 1325481fc6eSDavid Howells afs_fs_probe_cleanup(net); 133f044c884SDavid Howells afs_cell_purge(net); 134d2ddc776SDavid Howells afs_purge_servers(net); 135f044c884SDavid Howells error_cell_init: 136989782dcSDavid Howells net->live = false; 137f044c884SDavid Howells afs_proc_cleanup(net); 138f044c884SDavid Howells error_proc: 1396f8880d8SDavid Howells afs_put_sysnames(net->sysnames); 1406f8880d8SDavid Howells error_sysnames: 141989782dcSDavid Howells net->live = false; 142f044c884SDavid Howells return ret; 143f044c884SDavid Howells } 144f044c884SDavid Howells 145f044c884SDavid Howells /* 146f044c884SDavid Howells * Clean up and destroy an AFS network namespace record. 147f044c884SDavid Howells */ 1485b86d4ffSDavid Howells static void __net_exit afs_net_exit(struct net *net_ns) 149f044c884SDavid Howells { 1505b86d4ffSDavid Howells struct afs_net *net = afs_net(net_ns); 1515b86d4ffSDavid Howells 152f044c884SDavid Howells net->live = false; 1535481fc6eSDavid Howells afs_fs_probe_cleanup(net); 154f044c884SDavid Howells afs_cell_purge(net); 155d2ddc776SDavid Howells afs_purge_servers(net); 156e3b2ffe0SDavid Howells afs_close_socket(net); 157f044c884SDavid Howells afs_proc_cleanup(net); 1586f8880d8SDavid Howells afs_put_sysnames(net->sysnames); 159*f94f70d3SDavid Howells kfree_rcu(rcu_access_pointer(net->address_prefs), rcu); 160f044c884SDavid Howells } 161b908fe6bSDavid Howells 1625b86d4ffSDavid Howells static struct pernet_operations afs_net_ops = { 1635b86d4ffSDavid Howells .init = afs_net_init, 1645b86d4ffSDavid Howells .exit = afs_net_exit, 1655b86d4ffSDavid Howells .id = &afs_net_id, 1665b86d4ffSDavid Howells .size = sizeof(struct afs_net), 1675b86d4ffSDavid Howells }; 1685b86d4ffSDavid Howells 169b908fe6bSDavid Howells /* 1701da177e4SLinus Torvalds * initialise the AFS client FS module 1711da177e4SLinus Torvalds */ 1721da177e4SLinus Torvalds static int __init afs_init(void) 1731da177e4SLinus Torvalds { 174f044c884SDavid Howells int ret = -ENOMEM; 1751da177e4SLinus Torvalds 1761da177e4SLinus Torvalds printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 registering.\n"); 1771da177e4SLinus Torvalds 1780ad53eeeSTejun Heo afs_wq = alloc_workqueue("afs", 0, 0); 1790ad53eeeSTejun Heo if (!afs_wq) 180f044c884SDavid Howells goto error_afs_wq; 181f044c884SDavid Howells afs_async_calls = alloc_workqueue("kafsd", WQ_MEM_RECLAIM, 0); 182f044c884SDavid Howells if (!afs_async_calls) 183f044c884SDavid Howells goto error_async; 184f044c884SDavid Howells afs_lock_manager = alloc_workqueue("kafs_lockd", WQ_MEM_RECLAIM, 0); 185f044c884SDavid Howells if (!afs_lock_manager) 186f044c884SDavid Howells goto error_lockmgr; 1871da177e4SLinus Torvalds 1885399d522SDavid Howells ret = register_pernet_device(&afs_net_ops); 1891da177e4SLinus Torvalds if (ret < 0) 190f044c884SDavid Howells goto error_net; 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds /* register the filesystems */ 1931da177e4SLinus Torvalds ret = afs_fs_init(); 1941da177e4SLinus Torvalds if (ret < 0) 195ec26815aSDavid Howells goto error_fs; 1961da177e4SLinus Torvalds 1975b86d4ffSDavid Howells afs_proc_symlink = proc_symlink("fs/afs", NULL, "../self/net/afs"); 198a33d6266SDan Carpenter if (!afs_proc_symlink) { 199a33d6266SDan Carpenter ret = -ENOMEM; 2005b86d4ffSDavid Howells goto error_proc; 2015b86d4ffSDavid Howells } 2025b86d4ffSDavid Howells 2031da177e4SLinus Torvalds return ret; 2041da177e4SLinus Torvalds 2055b86d4ffSDavid Howells error_proc: 2065b86d4ffSDavid Howells afs_fs_exit(); 207ec26815aSDavid Howells error_fs: 2085399d522SDavid Howells unregister_pernet_device(&afs_net_ops); 209f044c884SDavid Howells error_net: 210f044c884SDavid Howells destroy_workqueue(afs_lock_manager); 211f044c884SDavid Howells error_lockmgr: 212f044c884SDavid Howells destroy_workqueue(afs_async_calls); 213f044c884SDavid Howells error_async: 2140ad53eeeSTejun Heo destroy_workqueue(afs_wq); 215f044c884SDavid Howells error_afs_wq: 216416351f2SDavid Howells rcu_barrier(); 2171da177e4SLinus Torvalds printk(KERN_ERR "kAFS: failed to register: %d\n", ret); 2181da177e4SLinus Torvalds return ret; 219ec26815aSDavid Howells } 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds /* XXX late_initcall is kludgy, but the only alternative seems to create 2221da177e4SLinus Torvalds * a transport upon the first mount, which is worse. Or is it? 2231da177e4SLinus Torvalds */ 2241da177e4SLinus Torvalds late_initcall(afs_init); /* must be called after net/ to create socket */ 225ec26815aSDavid Howells 2261da177e4SLinus Torvalds /* 2271da177e4SLinus Torvalds * clean up on module removal 2281da177e4SLinus Torvalds */ 2291da177e4SLinus Torvalds static void __exit afs_exit(void) 2301da177e4SLinus Torvalds { 2311da177e4SLinus Torvalds printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 unregistering.\n"); 2321da177e4SLinus Torvalds 2335b86d4ffSDavid Howells proc_remove(afs_proc_symlink); 2341da177e4SLinus Torvalds afs_fs_exit(); 2355399d522SDavid Howells unregister_pernet_device(&afs_net_ops); 236f044c884SDavid Howells destroy_workqueue(afs_lock_manager); 237f044c884SDavid Howells destroy_workqueue(afs_async_calls); 238f044c884SDavid Howells destroy_workqueue(afs_wq); 239be080a6fSDavid Howells afs_clean_up_permit_cache(); 240416351f2SDavid Howells rcu_barrier(); 241ec26815aSDavid Howells } 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds module_exit(afs_exit); 244