1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * Copyright (c) 2011 Bayard G. Bell. All rights reserved. 26 */ 27 28 #include <sys/errno.h> 29 #include <sys/param.h> 30 #include <sys/types.h> 31 #include <sys/user.h> 32 #include <sys/stat.h> 33 #include <sys/time.h> 34 #include <sys/vfs.h> 35 #include <sys/vnode.h> 36 #include <rpc/types.h> 37 #include <sys/mode.h> 38 #include <sys/cmn_err.h> 39 #include <sys/debug.h> 40 #include <sys/fs/cachefs_fs.h> 41 42 /* 43 * This is the loadable module wrapper. 44 */ 45 #include <sys/systm.h> 46 #include <sys/modctl.h> 47 #include <sys/syscall.h> 48 49 extern time_t time; 50 51 static int cachefs_init(int, char *); 52 static void cachefs_fini(); 53 54 static int cachefs_unloadable = 0; /* tunable */ 55 static boolean_t cachefs_up = B_FALSE; 56 57 uint_t cachefs_max_apop_inqueue = CACHEFS_MAX_APOP_INQUEUE; 58 59 /* 60 * this is a list of possible hash table sizes, for the `double 61 * hashing' algorithm described in rosen's `elementary number theory 62 * and its applications'. minimally, this needs to be a list of 63 * increasing prime integers, terminated by a 0. ideally, they should 64 * be the larger of twin primes; i.e. P and P-2 are both prime. 65 */ 66 67 int cachefs_hash_sizes[] = {5, 2029, 4093, 8089, 16363, 32719, 0}; 68 69 /* 70 * Module linkage information for the kernel. 71 */ 72 73 static vfsdef_t vfs_z = { 74 VFSDEF_VERSION, 75 CACHEFS_BASETYPE, 76 cachefs_init, 77 VSW_CANREMOUNT, 78 NULL 79 }; 80 81 static struct modlfs modlfs = { 82 &mod_fsops, 83 "cache filesystem", 84 &vfs_z 85 }; 86 87 static struct modlinkage modlinkage = { 88 MODREV_1, (void *)&modlfs, NULL 89 }; 90 91 int 92 _init(void) 93 { 94 int status; 95 96 status = mod_install(&modlinkage); 97 if (status != 0) { 98 /* 99 * Could not load module, clean up the work performed 100 * by cachefs_init() which was indirectly called by 101 * mod_installfs() which in turn was called by mod_install(). 102 */ 103 cachefs_fini(); 104 } 105 106 return (status); 107 } 108 109 int 110 _info(struct modinfo *modinfop) 111 { 112 return (mod_info(&modlinkage, modinfop)); 113 } 114 115 int 116 _fini(void) 117 { 118 int status; 119 120 if (!cachefs_unloadable) 121 return (EBUSY); 122 123 if ((status = mod_remove(&modlinkage)) == 0) { 124 /* 125 * Module has been unloaded, now clean up 126 */ 127 cachefs_fini(); 128 } 129 130 return (status); 131 } 132 133 extern kmutex_t cachefs_cachelock; /* Cache list mutex */ 134 extern kmutex_t cachefs_newnum_lock; 135 extern kmutex_t cachefs_kstat_key_lock; 136 extern kmutex_t cachefs_rename_lock; 137 extern kmutex_t cachefs_minor_lock; /* Lock for minor device map */ 138 extern kmutex_t cachefs_kmem_lock; 139 extern kmutex_t cachefs_async_lock; /* global async work count */ 140 extern major_t cachefs_major; 141 142 /* 143 * Cache initialization routine. This routine should only be called 144 * once. It performs the following tasks: 145 * - Initalize all global locks 146 * - Call sub-initialization routines (localize access to variables) 147 */ 148 static int 149 cachefs_init(int fstyp, char *name) 150 { 151 kstat_t *ksp; 152 int error; 153 154 ASSERT(cachefs_up == B_FALSE); 155 156 error = cachefs_init_vfsops(fstyp); 157 if (error != 0) 158 return (error); 159 160 error = cachefs_init_vnops(name); 161 if (error != 0) 162 return (error); 163 164 mutex_init(&cachefs_cachelock, NULL, MUTEX_DEFAULT, NULL); 165 mutex_init(&cachefs_newnum_lock, NULL, MUTEX_DEFAULT, NULL); 166 mutex_init(&cachefs_kstat_key_lock, NULL, MUTEX_DEFAULT, NULL); 167 mutex_init(&cachefs_kmem_lock, NULL, MUTEX_DEFAULT, NULL); 168 mutex_init(&cachefs_rename_lock, NULL, MUTEX_DEFAULT, NULL); 169 mutex_init(&cachefs_minor_lock, NULL, MUTEX_DEFAULT, NULL); 170 mutex_init(&cachefs_async_lock, NULL, MUTEX_DEFAULT, NULL); 171 #ifdef CFSRLDEBUG 172 mutex_init(&cachefs_rl_debug_mutex, NULL, MUTEX_DEFAULT, NULL); 173 #endif /* CFSRLDEBUG */ 174 175 /* 176 * set up kmem_cache entities 177 */ 178 179 cachefs_cnode_cache = kmem_cache_create("cachefs_cnode_cache", 180 sizeof (struct cnode), 0, NULL, NULL, NULL, NULL, NULL, 0); 181 cachefs_req_cache = kmem_cache_create("cachefs_async_request", 182 sizeof (struct cachefs_req), 0, 183 cachefs_req_create, cachefs_req_destroy, NULL, NULL, NULL, 0); 184 cachefs_fscache_cache = kmem_cache_create("cachefs_fscache", 185 sizeof (fscache_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 186 cachefs_filegrp_cache = kmem_cache_create("cachefs_filegrp", 187 sizeof (filegrp_t), 0, 188 filegrp_cache_create, filegrp_cache_destroy, NULL, NULL, NULL, 0); 189 cachefs_cache_kmcache = kmem_cache_create("cachefs_cache_t", 190 sizeof (cachefscache_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 191 192 /* 193 * set up the cachefs.0.key kstat 194 */ 195 196 cachefs_kstat_key = NULL; 197 cachefs_kstat_key_n = 0; 198 ksp = kstat_create("cachefs", 0, "key", "misc", KSTAT_TYPE_RAW, 1, 199 KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_VAR_SIZE); 200 if (ksp != NULL) { 201 ksp->ks_data = &cachefs_kstat_key; 202 ksp->ks_update = cachefs_kstat_key_update; 203 ksp->ks_snapshot = cachefs_kstat_key_snapshot; 204 ksp->ks_lock = &cachefs_kstat_key_lock; 205 kstat_install(ksp); 206 } 207 208 /* 209 * Assign unique major number for all nfs mounts 210 */ 211 212 if ((cachefs_major = getudev()) == -1) { 213 cmn_err(CE_WARN, 214 "cachefs: init: can't get unique device number"); 215 cachefs_major = 0; 216 } 217 cachefs_up = B_TRUE; 218 #ifdef CFSRLDEBUG 219 cachefs_dbvalid = time; 220 #endif /* CFSRLDEBUG */ 221 222 return (0); 223 } 224 225 /* 226 * Cache clean up routine. This routine is called if mod_install() failed 227 * and we have to clean up because the module could not be installed, 228 * or by _fini() when we're unloading the module. 229 */ 230 static void 231 cachefs_fini() 232 { 233 extern int cachefsfstyp; 234 extern struct vnodeops *cachefs_vnodeops; 235 236 if (cachefs_up == B_FALSE) { 237 /* 238 * cachefs_init() was not called on _init(), 239 * nothing to deallocate. 240 */ 241 return; 242 } 243 244 /* 245 * Clean up cachefs.0.key kstat. 246 * Currently, you can only do a 247 * modunload if cachefs_unloadable is nonzero, and that's 248 * pretty much just for debugging. however, if there ever 249 * comes a day when cachefs is more freely unloadable 250 * (e.g. the modunload daemon can do it normally), then we'll 251 * have to make changes in the stats_ API. this is because a 252 * stats_cookie_t holds the id # derived from here, and it 253 * will all go away at modunload time. thus, the API will 254 * need to somehow be more robust than is currently necessary. 255 */ 256 kstat_delete_byname("cachefs", 0, "key"); 257 258 if (cachefs_kstat_key != NULL) { 259 cachefs_kstat_key_t *key; 260 int i; 261 262 for (i = 0; i < cachefs_kstat_key_n; i++) { 263 key = cachefs_kstat_key + i; 264 265 cachefs_kmem_free((void *)(uintptr_t)key->ks_mountpoint, 266 strlen((char *)(uintptr_t)key->ks_mountpoint) + 1); 267 cachefs_kmem_free((void *)(uintptr_t)key->ks_backfs, 268 strlen((char *)(uintptr_t)key->ks_backfs) + 1); 269 cachefs_kmem_free((void *)(uintptr_t)key->ks_cachedir, 270 strlen((char *)(uintptr_t)key->ks_cachedir) + 1); 271 cachefs_kmem_free((void *)(uintptr_t)key->ks_cacheid, 272 strlen((char *)(uintptr_t)key->ks_cacheid) + 1); 273 } 274 275 cachefs_kmem_free(cachefs_kstat_key, 276 cachefs_kstat_key_n * sizeof (*cachefs_kstat_key)); 277 } 278 279 /* 280 * Clean up kmem_cache entities 281 */ 282 kmem_cache_destroy(cachefs_cache_kmcache); 283 kmem_cache_destroy(cachefs_filegrp_cache); 284 kmem_cache_destroy(cachefs_fscache_cache); 285 kmem_cache_destroy(cachefs_req_cache); 286 kmem_cache_destroy(cachefs_cnode_cache); 287 #ifdef CFSRLDEBUG 288 if (cachefs_rl_debug_cache != NULL) 289 kmem_cache_destroy(cachefs_rl_debug_cache); 290 #endif /* CFSRLDEBUG */ 291 292 /* 293 * Clean up the operations structures 294 */ 295 (void) vfs_freevfsops_by_type(cachefsfstyp); 296 vn_freevnodeops(cachefs_vnodeops); 297 298 /* 299 * Destroy mutexes 300 */ 301 #ifdef CFSRLDEBUG 302 mutex_destroy(&cachefs_rl_debug_mutex); 303 #endif /* CFSRLDEBUG */ 304 mutex_destroy(&cachefs_async_lock); 305 mutex_destroy(&cachefs_minor_lock); 306 mutex_destroy(&cachefs_rename_lock); 307 mutex_destroy(&cachefs_kmem_lock); 308 mutex_destroy(&cachefs_kstat_key_lock); 309 mutex_destroy(&cachefs_newnum_lock); 310 mutex_destroy(&cachefs_cachelock); 311 }