1 /* AFS client file system 2 * 3 * Copyright (C) 2002,5 Red Hat, Inc. All Rights Reserved. 4 * Written by David Howells (dhowells@redhat.com) 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 10 */ 11 12 #include <linux/module.h> 13 #include <linux/moduleparam.h> 14 #include <linux/init.h> 15 #include <linux/completion.h> 16 #include <linux/sched.h> 17 #include <linux/random.h> 18 #define CREATE_TRACE_POINTS 19 #include "internal.h" 20 21 MODULE_DESCRIPTION("AFS Client File System"); 22 MODULE_AUTHOR("Red Hat, Inc."); 23 MODULE_LICENSE("GPL"); 24 25 unsigned afs_debug; 26 module_param_named(debug, afs_debug, uint, S_IWUSR | S_IRUGO); 27 MODULE_PARM_DESC(debug, "AFS debugging mask"); 28 29 static char *rootcell; 30 31 module_param(rootcell, charp, 0); 32 MODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list"); 33 34 struct workqueue_struct *afs_wq; 35 struct afs_net __afs_net; 36 37 /* 38 * Initialise an AFS network namespace record. 39 */ 40 static int __net_init afs_net_init(struct afs_net *net) 41 { 42 int ret; 43 44 net->live = true; 45 generate_random_uuid((unsigned char *)&net->uuid); 46 47 INIT_WORK(&net->charge_preallocation_work, afs_charge_preallocation); 48 mutex_init(&net->socket_mutex); 49 INIT_LIST_HEAD(&net->cells); 50 rwlock_init(&net->cells_lock); 51 init_rwsem(&net->cells_sem); 52 init_waitqueue_head(&net->cells_freeable_wq); 53 init_rwsem(&net->proc_cells_sem); 54 INIT_LIST_HEAD(&net->proc_cells); 55 INIT_LIST_HEAD(&net->vl_updates); 56 INIT_LIST_HEAD(&net->vl_graveyard); 57 INIT_DELAYED_WORK(&net->vl_reaper, afs_vlocation_reaper); 58 INIT_DELAYED_WORK(&net->vl_updater, afs_vlocation_updater); 59 spin_lock_init(&net->vl_updates_lock); 60 spin_lock_init(&net->vl_graveyard_lock); 61 net->servers = RB_ROOT; 62 rwlock_init(&net->servers_lock); 63 INIT_LIST_HEAD(&net->server_graveyard); 64 spin_lock_init(&net->server_graveyard_lock); 65 INIT_DELAYED_WORK(&net->server_reaper, afs_reap_server); 66 67 /* Register the /proc stuff */ 68 ret = afs_proc_init(net); 69 if (ret < 0) 70 goto error_proc; 71 72 /* Initialise the cell DB */ 73 ret = afs_cell_init(net, rootcell); 74 if (ret < 0) 75 goto error_cell_init; 76 77 /* Create the RxRPC transport */ 78 ret = afs_open_socket(net); 79 if (ret < 0) 80 goto error_open_socket; 81 82 return 0; 83 84 error_open_socket: 85 afs_vlocation_purge(net); 86 afs_cell_purge(net); 87 error_cell_init: 88 afs_proc_cleanup(net); 89 error_proc: 90 return ret; 91 } 92 93 /* 94 * Clean up and destroy an AFS network namespace record. 95 */ 96 static void __net_exit afs_net_exit(struct afs_net *net) 97 { 98 net->live = false; 99 afs_close_socket(net); 100 afs_purge_servers(net); 101 afs_vlocation_purge(net); 102 afs_cell_purge(net); 103 afs_proc_cleanup(net); 104 } 105 106 /* 107 * initialise the AFS client FS module 108 */ 109 static int __init afs_init(void) 110 { 111 int ret = -ENOMEM; 112 113 printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 registering.\n"); 114 115 afs_wq = alloc_workqueue("afs", 0, 0); 116 if (!afs_wq) 117 goto error_afs_wq; 118 afs_async_calls = alloc_workqueue("kafsd", WQ_MEM_RECLAIM, 0); 119 if (!afs_async_calls) 120 goto error_async; 121 afs_vlocation_update_worker = 122 alloc_workqueue("kafs_vlupdated", WQ_MEM_RECLAIM, 0); 123 if (!afs_vlocation_update_worker) 124 goto error_vl_up; 125 afs_callback_update_worker = 126 alloc_ordered_workqueue("kafs_callbackd", WQ_MEM_RECLAIM); 127 if (!afs_callback_update_worker) 128 goto error_callback; 129 afs_lock_manager = alloc_workqueue("kafs_lockd", WQ_MEM_RECLAIM, 0); 130 if (!afs_lock_manager) 131 goto error_lockmgr; 132 133 #ifdef CONFIG_AFS_FSCACHE 134 /* we want to be able to cache */ 135 ret = fscache_register_netfs(&afs_cache_netfs); 136 if (ret < 0) 137 goto error_cache; 138 #endif 139 140 ret = afs_net_init(&__afs_net); 141 if (ret < 0) 142 goto error_net; 143 144 /* register the filesystems */ 145 ret = afs_fs_init(); 146 if (ret < 0) 147 goto error_fs; 148 149 return ret; 150 151 error_fs: 152 afs_net_exit(&__afs_net); 153 error_net: 154 #ifdef CONFIG_AFS_FSCACHE 155 fscache_unregister_netfs(&afs_cache_netfs); 156 error_cache: 157 #endif 158 destroy_workqueue(afs_lock_manager); 159 error_lockmgr: 160 destroy_workqueue(afs_callback_update_worker); 161 error_callback: 162 destroy_workqueue(afs_vlocation_update_worker); 163 error_vl_up: 164 destroy_workqueue(afs_async_calls); 165 error_async: 166 destroy_workqueue(afs_wq); 167 error_afs_wq: 168 rcu_barrier(); 169 printk(KERN_ERR "kAFS: failed to register: %d\n", ret); 170 return ret; 171 } 172 173 /* XXX late_initcall is kludgy, but the only alternative seems to create 174 * a transport upon the first mount, which is worse. Or is it? 175 */ 176 late_initcall(afs_init); /* must be called after net/ to create socket */ 177 178 /* 179 * clean up on module removal 180 */ 181 static void __exit afs_exit(void) 182 { 183 printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 unregistering.\n"); 184 185 afs_fs_exit(); 186 afs_net_exit(&__afs_net); 187 #ifdef CONFIG_AFS_FSCACHE 188 fscache_unregister_netfs(&afs_cache_netfs); 189 #endif 190 destroy_workqueue(afs_lock_manager); 191 destroy_workqueue(afs_callback_update_worker); 192 destroy_workqueue(afs_vlocation_update_worker); 193 destroy_workqueue(afs_async_calls); 194 destroy_workqueue(afs_wq); 195 rcu_barrier(); 196 } 197 198 module_exit(afs_exit); 199