at v2.6.19 286 lines 7.7 kB view raw
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 30struct rxrpc_transport *afs_transport; 31 32static int afs_adding_peer(struct rxrpc_peer *peer); 33static void afs_discarding_peer(struct rxrpc_peer *peer); 34 35 36MODULE_DESCRIPTION("AFS Client File System"); 37MODULE_AUTHOR("Red Hat, Inc."); 38MODULE_LICENSE("GPL"); 39 40static char *rootcell; 41 42module_param(rootcell, charp, 0); 43MODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list"); 44 45 46static struct rxrpc_peer_ops afs_peer_ops = { 47 .adding = afs_adding_peer, 48 .discarding = afs_discarding_peer, 49}; 50 51struct list_head afs_cb_hash_tbl[AFS_CB_HASH_COUNT]; 52DEFINE_SPINLOCK(afs_cb_hash_lock); 53 54#ifdef AFS_CACHING_SUPPORT 55static struct cachefs_netfs_operations afs_cache_ops = { 56 .get_page_cookie = afs_cache_get_page_cookie, 57}; 58 59struct 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 */ 70static 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 */ 153late_initcall(afs_init); /* must be called after net/ to create socket */ 154/*****************************************************************************/ 155/* 156 * clean up on module removal 157 */ 158static 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 177module_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 */ 186static 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 */ 219static 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 249void __cyg_profile_func_enter (void *this_fn, void *call_site) 250__attribute__((no_instrument_function)); 251 252void __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 268void __cyg_profile_func_exit(void *this_fn, void *call_site) 269__attribute__((no_instrument_function)); 270 271void __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