1 /* main.c: AFS client file system 2 * 3 * Copyright (C) 2002 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/sched.h> 16 #include <linux/completion.h> 17 #include <rxrpc/rxrpc.h> 18 #include <rxrpc/transport.h> 19 #include <rxrpc/call.h> 20 #include <rxrpc/peer.h> 21 #include "cache.h" 22 #include "cell.h" 23 #include "server.h" 24 #include "fsclient.h" 25 #include "cmservice.h" 26 #include "kafstimod.h" 27 #include "kafsasyncd.h" 28 #include "internal.h" 29 30 struct rxrpc_transport *afs_transport; 31 32 static int afs_adding_peer(struct rxrpc_peer *peer); 33 static void afs_discarding_peer(struct rxrpc_peer *peer); 34 35 36 MODULE_DESCRIPTION("AFS Client File System"); 37 MODULE_AUTHOR("Red Hat, Inc."); 38 MODULE_LICENSE("GPL"); 39 40 static char *rootcell; 41 42 module_param(rootcell, charp, 0); 43 MODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list"); 44 45 46 static struct rxrpc_peer_ops afs_peer_ops = { 47 .adding = afs_adding_peer, 48 .discarding = afs_discarding_peer, 49 }; 50 51 struct list_head afs_cb_hash_tbl[AFS_CB_HASH_COUNT]; 52 DEFINE_SPINLOCK(afs_cb_hash_lock); 53 54 #ifdef AFS_CACHING_SUPPORT 55 static struct cachefs_netfs_operations afs_cache_ops = { 56 .get_page_cookie = afs_cache_get_page_cookie, 57 }; 58 59 struct cachefs_netfs afs_cache_netfs = { 60 .name = "afs", 61 .version = 0, 62 .ops = &afs_cache_ops, 63 }; 64 #endif 65 66 /*****************************************************************************/ 67 /* 68 * initialise the AFS client FS module 69 */ 70 static int __init afs_init(void) 71 { 72 int loop, ret; 73 74 printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 registering.\n"); 75 76 /* initialise the callback hash table */ 77 spin_lock_init(&afs_cb_hash_lock); 78 for (loop = AFS_CB_HASH_COUNT - 1; loop >= 0; loop--) 79 INIT_LIST_HEAD(&afs_cb_hash_tbl[loop]); 80 81 /* register the /proc stuff */ 82 ret = afs_proc_init(); 83 if (ret < 0) 84 return ret; 85 86 #ifdef AFS_CACHING_SUPPORT 87 /* we want to be able to cache */ 88 ret = cachefs_register_netfs(&afs_cache_netfs, 89 &afs_cache_cell_index_def); 90 if (ret < 0) 91 goto error; 92 #endif 93 94 #ifdef CONFIG_KEYS_TURNED_OFF 95 ret = afs_key_register(); 96 if (ret < 0) 97 goto error_cache; 98 #endif 99 100 /* initialise the cell DB */ 101 ret = afs_cell_init(rootcell); 102 if (ret < 0) 103 goto error_keys; 104 105 /* start the timeout daemon */ 106 ret = afs_kafstimod_start(); 107 if (ret < 0) 108 goto error_keys; 109 110 /* start the async operation daemon */ 111 ret = afs_kafsasyncd_start(); 112 if (ret < 0) 113 goto error_kafstimod; 114 115 /* create the RxRPC transport */ 116 ret = rxrpc_create_transport(7001, &afs_transport); 117 if (ret < 0) 118 goto error_kafsasyncd; 119 120 afs_transport->peer_ops = &afs_peer_ops; 121 122 /* register the filesystems */ 123 ret = afs_fs_init(); 124 if (ret < 0) 125 goto error_transport; 126 127 return ret; 128 129 error_transport: 130 rxrpc_put_transport(afs_transport); 131 error_kafsasyncd: 132 afs_kafsasyncd_stop(); 133 error_kafstimod: 134 afs_kafstimod_stop(); 135 error_keys: 136 #ifdef CONFIG_KEYS_TURNED_OFF 137 afs_key_unregister(); 138 error_cache: 139 #endif 140 #ifdef AFS_CACHING_SUPPORT 141 cachefs_unregister_netfs(&afs_cache_netfs); 142 error: 143 #endif 144 afs_cell_purge(); 145 afs_proc_cleanup(); 146 printk(KERN_ERR "kAFS: failed to register: %d\n", ret); 147 return ret; 148 } /* end afs_init() */ 149 150 /* XXX late_initcall is kludgy, but the only alternative seems to create 151 * a transport upon the first mount, which is worse. Or is it? 152 */ 153 late_initcall(afs_init); /* must be called after net/ to create socket */ 154 /*****************************************************************************/ 155 /* 156 * clean up on module removal 157 */ 158 static void __exit afs_exit(void) 159 { 160 printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 unregistering.\n"); 161 162 afs_fs_exit(); 163 rxrpc_put_transport(afs_transport); 164 afs_kafstimod_stop(); 165 afs_kafsasyncd_stop(); 166 afs_cell_purge(); 167 #ifdef CONFIG_KEYS_TURNED_OFF 168 afs_key_unregister(); 169 #endif 170 #ifdef AFS_CACHING_SUPPORT 171 cachefs_unregister_netfs(&afs_cache_netfs); 172 #endif 173 afs_proc_cleanup(); 174 175 } /* end afs_exit() */ 176 177 module_exit(afs_exit); 178 179 /*****************************************************************************/ 180 /* 181 * notification that new peer record is being added 182 * - called from krxsecd 183 * - return an error to induce an abort 184 * - mustn't sleep (caller holds an rwlock) 185 */ 186 static int afs_adding_peer(struct rxrpc_peer *peer) 187 { 188 struct afs_server *server; 189 int ret; 190 191 _debug("kAFS: Adding new peer %08x\n", ntohl(peer->addr.s_addr)); 192 193 /* determine which server the peer resides in (if any) */ 194 ret = afs_server_find_by_peer(peer, &server); 195 if (ret < 0) 196 return ret; /* none that we recognise, so abort */ 197 198 _debug("Server %p{u=%d}\n", server, atomic_read(&server->usage)); 199 200 _debug("Cell %p{u=%d}\n", 201 server->cell, atomic_read(&server->cell->usage)); 202 203 /* cross-point the structs under a global lock */ 204 spin_lock(&afs_server_peer_lock); 205 peer->user = server; 206 server->peer = peer; 207 spin_unlock(&afs_server_peer_lock); 208 209 afs_put_server(server); 210 211 return 0; 212 } /* end afs_adding_peer() */ 213 214 /*****************************************************************************/ 215 /* 216 * notification that a peer record is being discarded 217 * - called from krxiod or krxsecd 218 */ 219 static void afs_discarding_peer(struct rxrpc_peer *peer) 220 { 221 struct afs_server *server; 222 223 _enter("%p",peer); 224 225 _debug("Discarding peer %08x (rtt=%lu.%lumS)\n", 226 ntohl(peer->addr.s_addr), 227 (long) (peer->rtt / 1000), 228 (long) (peer->rtt % 1000)); 229 230 /* uncross-point the structs under a global lock */ 231 spin_lock(&afs_server_peer_lock); 232 server = peer->user; 233 if (server) { 234 peer->user = NULL; 235 server->peer = NULL; 236 } 237 spin_unlock(&afs_server_peer_lock); 238 239 _leave(""); 240 241 } /* end afs_discarding_peer() */ 242 243 /*****************************************************************************/ 244 /* 245 * clear the dead space between task_struct and kernel stack 246 * - called by supplying -finstrument-functions to gcc 247 */ 248 #if 0 249 void __cyg_profile_func_enter (void *this_fn, void *call_site) 250 __attribute__((no_instrument_function)); 251 252 void __cyg_profile_func_enter (void *this_fn, void *call_site) 253 { 254 asm volatile(" movl %%esp,%%edi \n" 255 " andl %0,%%edi \n" 256 " addl %1,%%edi \n" 257 " movl %%esp,%%ecx \n" 258 " subl %%edi,%%ecx \n" 259 " shrl $2,%%ecx \n" 260 " movl $0xedededed,%%eax \n" 261 " rep stosl \n" 262 : 263 : "i"(~(THREAD_SIZE - 1)), "i"(sizeof(struct thread_info)) 264 : "eax", "ecx", "edi", "memory", "cc" 265 ); 266 } 267 268 void __cyg_profile_func_exit(void *this_fn, void *call_site) 269 __attribute__((no_instrument_function)); 270 271 void __cyg_profile_func_exit(void *this_fn, void *call_site) 272 { 273 asm volatile(" movl %%esp,%%edi \n" 274 " andl %0,%%edi \n" 275 " addl %1,%%edi \n" 276 " movl %%esp,%%ecx \n" 277 " subl %%edi,%%ecx \n" 278 " shrl $2,%%ecx \n" 279 " movl $0xdadadada,%%eax \n" 280 " rep stosl \n" 281 : 282 : "i"(~(THREAD_SIZE - 1)), "i"(sizeof(struct thread_info)) 283 : "eax", "ecx", "edi", "memory", "cc" 284 ); 285 } 286 #endif 287