1 1.73 riastrad /* $NetBSD: vfs_trans.c,v 1.73 2024/12/07 02:27:38 riastradh Exp $ */ 2 1.1 hannken 3 1.1 hannken /*- 4 1.63 ad * Copyright (c) 2007, 2020 The NetBSD Foundation, Inc. 5 1.1 hannken * All rights reserved. 6 1.1 hannken * 7 1.1 hannken * This code is derived from software contributed to The NetBSD Foundation 8 1.1 hannken * by Juergen Hannken-Illjes. 9 1.1 hannken * 10 1.1 hannken * Redistribution and use in source and binary forms, with or without 11 1.1 hannken * modification, are permitted provided that the following conditions 12 1.1 hannken * are met: 13 1.1 hannken * 1. Redistributions of source code must retain the above copyright 14 1.1 hannken * notice, this list of conditions and the following disclaimer. 15 1.1 hannken * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 hannken * notice, this list of conditions and the following disclaimer in the 17 1.1 hannken * documentation and/or other materials provided with the distribution. 18 1.1 hannken * 19 1.1 hannken * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 hannken * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 hannken * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 hannken * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 hannken * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 hannken * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 hannken * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 hannken * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 hannken * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 hannken * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 hannken * POSSIBILITY OF SUCH DAMAGE. 30 1.1 hannken */ 31 1.1 hannken 32 1.1 hannken #include <sys/cdefs.h> 33 1.73 riastrad __KERNEL_RCSID(0, "$NetBSD: vfs_trans.c,v 1.73 2024/12/07 02:27:38 riastradh Exp $"); 34 1.1 hannken 35 1.1 hannken /* 36 1.1 hannken * File system transaction operations. 37 1.1 hannken */ 38 1.1 hannken 39 1.34 pooka #ifdef _KERNEL_OPT 40 1.1 hannken #include "opt_ddb.h" 41 1.34 pooka #endif 42 1.1 hannken 43 1.1 hannken #include <sys/param.h> 44 1.71 riastrad #include <sys/types.h> 45 1.71 riastrad 46 1.26 hannken #include <sys/atomic.h> 47 1.24 pooka #include <sys/buf.h> 48 1.71 riastrad #include <sys/fstrans.h> 49 1.66 hannken #include <sys/hash.h> 50 1.12 hannken #include <sys/kmem.h> 51 1.1 hannken #include <sys/mount.h> 52 1.71 riastrad #include <sys/pool.h> 53 1.71 riastrad #include <sys/proc.h> 54 1.26 hannken #include <sys/pserialize.h> 55 1.73 riastrad #include <sys/sdt.h> 56 1.71 riastrad #include <sys/systm.h> 57 1.1 hannken #include <sys/vnode.h> 58 1.1 hannken 59 1.69 riastrad #include <miscfs/deadfs/deadfs.h> 60 1.12 hannken #include <miscfs/specfs/specdev.h> 61 1.1 hannken 62 1.66 hannken #define FSTRANS_MOUNT_HASHSIZE 32 63 1.66 hannken 64 1.46 hannken enum fstrans_lock_type { 65 1.51 hannken FSTRANS_LAZY, /* Granted while not suspended */ 66 1.61 hannken FSTRANS_SHARED /* Granted while not suspending */ 67 1.46 hannken }; 68 1.46 hannken 69 1.16 ad struct fscow_handler { 70 1.26 hannken LIST_ENTRY(fscow_handler) ch_list; 71 1.16 ad int (*ch_func)(void *, struct buf *, bool); 72 1.16 ad void *ch_arg; 73 1.16 ad }; 74 1.1 hannken struct fstrans_lwp_info { 75 1.1 hannken struct fstrans_lwp_info *fli_succ; 76 1.26 hannken struct lwp *fli_self; 77 1.1 hannken struct mount *fli_mount; 78 1.58 hannken struct fstrans_lwp_info *fli_alias; 79 1.54 hannken struct fstrans_mount_info *fli_mountinfo; 80 1.20 hannken int fli_trans_cnt; 81 1.59 hannken int fli_alias_cnt; 82 1.20 hannken int fli_cow_cnt; 83 1.1 hannken enum fstrans_lock_type fli_lock_type; 84 1.26 hannken LIST_ENTRY(fstrans_lwp_info) fli_list; 85 1.1 hannken }; 86 1.1 hannken struct fstrans_mount_info { 87 1.1 hannken enum fstrans_state fmi_state; 88 1.26 hannken unsigned int fmi_ref_cnt; 89 1.54 hannken bool fmi_gone; 90 1.26 hannken bool fmi_cow_change; 91 1.66 hannken SLIST_ENTRY(fstrans_mount_info) fmi_hash; 92 1.26 hannken LIST_HEAD(, fscow_handler) fmi_cow_handler; 93 1.54 hannken struct mount *fmi_mount; 94 1.67 hannken struct fstrans_mount_info *fmi_lower_info; 95 1.61 hannken struct lwp *fmi_owner; 96 1.1 hannken }; 97 1.66 hannken SLIST_HEAD(fstrans_mount_hashhead, fstrans_mount_info); 98 1.1 hannken 99 1.63 ad static kmutex_t vfs_suspend_lock /* Serialize suspensions. */ 100 1.63 ad __cacheline_aligned; 101 1.63 ad static kmutex_t fstrans_lock /* Fstrans big lock. */ 102 1.63 ad __cacheline_aligned; 103 1.26 hannken static kcondvar_t fstrans_state_cv; /* Fstrans or cow state changed. */ 104 1.26 hannken static kcondvar_t fstrans_count_cv; /* Fstrans or cow count changed. */ 105 1.26 hannken static pserialize_t fstrans_psz; /* Pserialize state. */ 106 1.26 hannken static LIST_HEAD(fstrans_lwp_head, fstrans_lwp_info) fstrans_fli_head; 107 1.26 hannken /* List of all fstrans_lwp_info. */ 108 1.63 ad static pool_cache_t fstrans_lwp_cache; /* Cache of fstrans_lwp_info. */ 109 1.63 ad 110 1.66 hannken static u_long fstrans_mount_hashmask; 111 1.66 hannken static struct fstrans_mount_hashhead *fstrans_mount_hashtab; 112 1.54 hannken static int fstrans_gone_count; /* Number of fstrans_mount_info gone. */ 113 1.1 hannken 114 1.66 hannken static inline uint32_t fstrans_mount_hash(struct mount *); 115 1.66 hannken static inline struct fstrans_mount_info *fstrans_mount_get(struct mount *); 116 1.54 hannken static void fstrans_mount_dtor(struct fstrans_mount_info *); 117 1.47 hannken static void fstrans_clear_lwp_info(void); 118 1.48 hannken static inline struct fstrans_lwp_info * 119 1.48 hannken fstrans_get_lwp_info(struct mount *, bool); 120 1.48 hannken static struct fstrans_lwp_info *fstrans_alloc_lwp_info(struct mount *); 121 1.63 ad static int fstrans_lwp_pcc(void *, void *, int); 122 1.63 ad static void fstrans_lwp_pcd(void *, void *); 123 1.46 hannken static inline int _fstrans_start(struct mount *, enum fstrans_lock_type, int); 124 1.61 hannken static bool grant_lock(const struct fstrans_mount_info *, 125 1.61 hannken const enum fstrans_lock_type); 126 1.54 hannken static bool state_change_done(const struct fstrans_mount_info *); 127 1.54 hannken static bool cow_state_change_done(const struct fstrans_mount_info *); 128 1.54 hannken static void cow_change_enter(struct fstrans_mount_info *); 129 1.54 hannken static void cow_change_done(struct fstrans_mount_info *); 130 1.1 hannken 131 1.1 hannken /* 132 1.26 hannken * Initialize. 133 1.1 hannken */ 134 1.1 hannken void 135 1.1 hannken fstrans_init(void) 136 1.1 hannken { 137 1.7 ad 138 1.4 ad mutex_init(&vfs_suspend_lock, MUTEX_DEFAULT, IPL_NONE); 139 1.26 hannken mutex_init(&fstrans_lock, MUTEX_DEFAULT, IPL_NONE); 140 1.26 hannken cv_init(&fstrans_state_cv, "fstchg"); 141 1.26 hannken cv_init(&fstrans_count_cv, "fstcnt"); 142 1.26 hannken fstrans_psz = pserialize_create(); 143 1.26 hannken LIST_INIT(&fstrans_fli_head); 144 1.63 ad fstrans_lwp_cache = pool_cache_init(sizeof(struct fstrans_lwp_info), 145 1.63 ad coherency_unit, 0, 0, "fstlwp", NULL, IPL_NONE, 146 1.63 ad fstrans_lwp_pcc, fstrans_lwp_pcd, NULL); 147 1.63 ad KASSERT(fstrans_lwp_cache != NULL); 148 1.66 hannken fstrans_mount_hashtab = hashinit(FSTRANS_MOUNT_HASHSIZE, HASH_SLIST, 149 1.66 hannken true, &fstrans_mount_hashmask); 150 1.63 ad } 151 1.63 ad 152 1.63 ad /* 153 1.63 ad * pool_cache constructor for fstrans_lwp_info. Updating the global list 154 1.63 ad * produces cache misses on MP. Minimise by keeping free entries on list. 155 1.63 ad */ 156 1.63 ad int 157 1.63 ad fstrans_lwp_pcc(void *arg, void *obj, int flags) 158 1.63 ad { 159 1.63 ad struct fstrans_lwp_info *fli = obj; 160 1.63 ad 161 1.63 ad memset(fli, 0, sizeof(*fli)); 162 1.63 ad 163 1.63 ad mutex_enter(&fstrans_lock); 164 1.63 ad LIST_INSERT_HEAD(&fstrans_fli_head, fli, fli_list); 165 1.63 ad mutex_exit(&fstrans_lock); 166 1.63 ad 167 1.63 ad return 0; 168 1.63 ad } 169 1.63 ad 170 1.63 ad /* 171 1.63 ad * pool_cache destructor 172 1.63 ad */ 173 1.63 ad void 174 1.63 ad fstrans_lwp_pcd(void *arg, void *obj) 175 1.63 ad { 176 1.63 ad struct fstrans_lwp_info *fli = obj; 177 1.63 ad 178 1.63 ad mutex_enter(&fstrans_lock); 179 1.63 ad LIST_REMOVE(fli, fli_list); 180 1.63 ad mutex_exit(&fstrans_lock); 181 1.1 hannken } 182 1.1 hannken 183 1.1 hannken /* 184 1.26 hannken * Deallocate lwp state. 185 1.1 hannken */ 186 1.57 hannken void 187 1.57 hannken fstrans_lwp_dtor(lwp_t *l) 188 1.1 hannken { 189 1.1 hannken struct fstrans_lwp_info *fli, *fli_next; 190 1.1 hannken 191 1.63 ad if (l->l_fstrans == NULL) 192 1.63 ad return; 193 1.63 ad 194 1.63 ad mutex_enter(&fstrans_lock); 195 1.57 hannken for (fli = l->l_fstrans; fli; fli = fli_next) { 196 1.20 hannken KASSERT(fli->fli_trans_cnt == 0); 197 1.20 hannken KASSERT(fli->fli_cow_cnt == 0); 198 1.57 hannken KASSERT(fli->fli_self == l); 199 1.26 hannken if (fli->fli_mount != NULL) 200 1.54 hannken fstrans_mount_dtor(fli->fli_mountinfo); 201 1.1 hannken fli_next = fli->fli_succ; 202 1.59 hannken fli->fli_alias_cnt = 0; 203 1.30 hannken fli->fli_mount = NULL; 204 1.54 hannken fli->fli_alias = NULL; 205 1.54 hannken fli->fli_mountinfo = NULL; 206 1.30 hannken fli->fli_self = NULL; 207 1.1 hannken } 208 1.63 ad mutex_exit(&fstrans_lock); 209 1.57 hannken 210 1.63 ad for (fli = l->l_fstrans; fli; fli = fli_next) { 211 1.63 ad fli_next = fli->fli_succ; 212 1.63 ad pool_cache_put(fstrans_lwp_cache, fli); 213 1.63 ad } 214 1.57 hannken l->l_fstrans = NULL; 215 1.26 hannken } 216 1.26 hannken 217 1.26 hannken /* 218 1.66 hannken * mount pointer to hash 219 1.66 hannken */ 220 1.66 hannken static inline uint32_t 221 1.66 hannken fstrans_mount_hash(struct mount *mp) 222 1.66 hannken { 223 1.66 hannken 224 1.66 hannken return hash32_buf(&mp, sizeof(mp), HASH32_BUF_INIT) & 225 1.66 hannken fstrans_mount_hashmask; 226 1.66 hannken } 227 1.66 hannken 228 1.66 hannken /* 229 1.66 hannken * retrieve fstrans_mount_info by mount or NULL 230 1.66 hannken */ 231 1.66 hannken static inline struct fstrans_mount_info * 232 1.66 hannken fstrans_mount_get(struct mount *mp) 233 1.66 hannken { 234 1.66 hannken uint32_t indx; 235 1.67 hannken struct fstrans_mount_info *fmi, *fmi_lower; 236 1.66 hannken 237 1.66 hannken KASSERT(mutex_owned(&fstrans_lock)); 238 1.66 hannken 239 1.66 hannken indx = fstrans_mount_hash(mp); 240 1.66 hannken SLIST_FOREACH(fmi, &fstrans_mount_hashtab[indx], fmi_hash) { 241 1.66 hannken if (fmi->fmi_mount == mp) { 242 1.67 hannken if (__predict_false(mp->mnt_lower != NULL && 243 1.67 hannken fmi->fmi_lower_info == NULL)) { 244 1.67 hannken /* 245 1.67 hannken * Intern the lower/lowest mount into 246 1.67 hannken * this mount info on first lookup. 247 1.67 hannken */ 248 1.67 hannken KASSERT(fmi->fmi_ref_cnt == 1); 249 1.67 hannken 250 1.67 hannken fmi_lower = fstrans_mount_get(mp->mnt_lower); 251 1.67 hannken if (fmi_lower && fmi_lower->fmi_lower_info) 252 1.67 hannken fmi_lower = fmi_lower->fmi_lower_info; 253 1.67 hannken if (fmi_lower == NULL) 254 1.67 hannken return NULL; 255 1.67 hannken fmi->fmi_lower_info = fmi_lower; 256 1.67 hannken fmi->fmi_lower_info->fmi_ref_cnt += 1; 257 1.67 hannken } 258 1.66 hannken return fmi; 259 1.66 hannken } 260 1.66 hannken } 261 1.66 hannken 262 1.66 hannken return NULL; 263 1.66 hannken } 264 1.66 hannken 265 1.66 hannken /* 266 1.26 hannken * Dereference mount state. 267 1.26 hannken */ 268 1.26 hannken static void 269 1.54 hannken fstrans_mount_dtor(struct fstrans_mount_info *fmi) 270 1.26 hannken { 271 1.26 hannken 272 1.63 ad KASSERT(mutex_owned(&fstrans_lock)); 273 1.35 hannken 274 1.35 hannken KASSERT(fmi != NULL); 275 1.35 hannken fmi->fmi_ref_cnt -= 1; 276 1.63 ad if (__predict_true(fmi->fmi_ref_cnt > 0)) { 277 1.26 hannken return; 278 1.35 hannken } 279 1.26 hannken 280 1.26 hannken KASSERT(fmi->fmi_state == FSTRANS_NORMAL); 281 1.26 hannken KASSERT(LIST_FIRST(&fmi->fmi_cow_handler) == NULL); 282 1.61 hannken KASSERT(fmi->fmi_owner == NULL); 283 1.26 hannken 284 1.67 hannken if (fmi->fmi_lower_info) 285 1.67 hannken fstrans_mount_dtor(fmi->fmi_lower_info); 286 1.67 hannken 287 1.54 hannken KASSERT(fstrans_gone_count > 0); 288 1.54 hannken fstrans_gone_count -= 1; 289 1.26 hannken 290 1.70 hannken KASSERT(fmi->fmi_mount->mnt_lower == NULL); 291 1.70 hannken 292 1.54 hannken kmem_free(fmi->fmi_mount, sizeof(*fmi->fmi_mount)); 293 1.35 hannken kmem_free(fmi, sizeof(*fmi)); 294 1.1 hannken } 295 1.1 hannken 296 1.1 hannken /* 297 1.26 hannken * Allocate mount state. 298 1.1 hannken */ 299 1.16 ad int 300 1.16 ad fstrans_mount(struct mount *mp) 301 1.1 hannken { 302 1.66 hannken uint32_t indx; 303 1.31 matt struct fstrans_mount_info *newfmi; 304 1.16 ad 305 1.66 hannken indx = fstrans_mount_hash(mp); 306 1.66 hannken 307 1.32 pooka newfmi = kmem_alloc(sizeof(*newfmi), KM_SLEEP); 308 1.31 matt newfmi->fmi_state = FSTRANS_NORMAL; 309 1.31 matt newfmi->fmi_ref_cnt = 1; 310 1.54 hannken newfmi->fmi_gone = false; 311 1.31 matt LIST_INIT(&newfmi->fmi_cow_handler); 312 1.31 matt newfmi->fmi_cow_change = false; 313 1.54 hannken newfmi->fmi_mount = mp; 314 1.67 hannken newfmi->fmi_lower_info = NULL; 315 1.61 hannken newfmi->fmi_owner = NULL; 316 1.16 ad 317 1.63 ad mutex_enter(&fstrans_lock); 318 1.66 hannken SLIST_INSERT_HEAD(&fstrans_mount_hashtab[indx], newfmi, fmi_hash); 319 1.63 ad mutex_exit(&fstrans_lock); 320 1.1 hannken 321 1.16 ad return 0; 322 1.1 hannken } 323 1.1 hannken 324 1.1 hannken /* 325 1.26 hannken * Deallocate mount state. 326 1.1 hannken */ 327 1.16 ad void 328 1.16 ad fstrans_unmount(struct mount *mp) 329 1.1 hannken { 330 1.66 hannken uint32_t indx; 331 1.66 hannken struct fstrans_mount_info *fmi; 332 1.54 hannken 333 1.66 hannken indx = fstrans_mount_hash(mp); 334 1.1 hannken 335 1.63 ad mutex_enter(&fstrans_lock); 336 1.66 hannken fmi = fstrans_mount_get(mp); 337 1.66 hannken KASSERT(fmi != NULL); 338 1.54 hannken fmi->fmi_gone = true; 339 1.66 hannken SLIST_REMOVE(&fstrans_mount_hashtab[indx], 340 1.66 hannken fmi, fstrans_mount_info, fmi_hash); 341 1.54 hannken fstrans_gone_count += 1; 342 1.54 hannken fstrans_mount_dtor(fmi); 343 1.63 ad mutex_exit(&fstrans_lock); 344 1.1 hannken } 345 1.1 hannken 346 1.1 hannken /* 347 1.47 hannken * Clear mount entries whose mount is gone. 348 1.20 hannken */ 349 1.47 hannken static void 350 1.47 hannken fstrans_clear_lwp_info(void) 351 1.20 hannken { 352 1.63 ad struct fstrans_lwp_info **p, *fli, *tofree = NULL; 353 1.20 hannken 354 1.26 hannken /* 355 1.47 hannken * Scan our list clearing entries whose mount is gone. 356 1.26 hannken */ 357 1.63 ad mutex_enter(&fstrans_lock); 358 1.58 hannken for (p = &curlwp->l_fstrans; *p; ) { 359 1.54 hannken fli = *p; 360 1.47 hannken if (fli->fli_mount != NULL && 361 1.54 hannken fli->fli_mountinfo->fmi_gone && 362 1.59 hannken fli->fli_trans_cnt == 0 && 363 1.59 hannken fli->fli_cow_cnt == 0 && 364 1.59 hannken fli->fli_alias_cnt == 0) { 365 1.54 hannken *p = (*p)->fli_succ; 366 1.54 hannken fstrans_mount_dtor(fli->fli_mountinfo); 367 1.59 hannken if (fli->fli_alias) { 368 1.59 hannken KASSERT(fli->fli_alias->fli_alias_cnt > 0); 369 1.59 hannken fli->fli_alias->fli_alias_cnt--; 370 1.59 hannken } 371 1.26 hannken fli->fli_mount = NULL; 372 1.54 hannken fli->fli_alias = NULL; 373 1.54 hannken fli->fli_mountinfo = NULL; 374 1.54 hannken fli->fli_self = NULL; 375 1.59 hannken p = &curlwp->l_fstrans; 376 1.63 ad fli->fli_succ = tofree; 377 1.63 ad tofree = fli; 378 1.58 hannken } else { 379 1.58 hannken p = &(*p)->fli_succ; 380 1.26 hannken } 381 1.20 hannken } 382 1.58 hannken #ifdef DIAGNOSTIC 383 1.58 hannken for (fli = curlwp->l_fstrans; fli; fli = fli->fli_succ) 384 1.58 hannken if (fli->fli_alias != NULL) 385 1.58 hannken KASSERT(fli->fli_alias->fli_self == curlwp); 386 1.58 hannken #endif /* DIAGNOSTIC */ 387 1.63 ad mutex_exit(&fstrans_lock); 388 1.63 ad 389 1.63 ad while (tofree != NULL) { 390 1.63 ad fli = tofree; 391 1.63 ad tofree = fli->fli_succ; 392 1.63 ad pool_cache_put(fstrans_lwp_cache, fli); 393 1.63 ad } 394 1.47 hannken } 395 1.47 hannken 396 1.47 hannken /* 397 1.48 hannken * Allocate and return per lwp info for this mount. 398 1.47 hannken */ 399 1.47 hannken static struct fstrans_lwp_info * 400 1.48 hannken fstrans_alloc_lwp_info(struct mount *mp) 401 1.47 hannken { 402 1.67 hannken struct fstrans_lwp_info *fli, *fli_lower; 403 1.47 hannken struct fstrans_mount_info *fmi; 404 1.47 hannken 405 1.57 hannken for (fli = curlwp->l_fstrans; fli; fli = fli->fli_succ) { 406 1.54 hannken if (fli->fli_mount == mp) 407 1.54 hannken return fli; 408 1.54 hannken } 409 1.54 hannken 410 1.47 hannken /* 411 1.67 hannken * Lookup mount info and get lower mount per lwp info. 412 1.67 hannken */ 413 1.67 hannken mutex_enter(&fstrans_lock); 414 1.67 hannken fmi = fstrans_mount_get(mp); 415 1.67 hannken if (fmi == NULL) { 416 1.67 hannken mutex_exit(&fstrans_lock); 417 1.67 hannken return NULL; 418 1.67 hannken } 419 1.67 hannken fmi->fmi_ref_cnt += 1; 420 1.67 hannken mutex_exit(&fstrans_lock); 421 1.67 hannken 422 1.67 hannken if (fmi->fmi_lower_info) { 423 1.67 hannken fli_lower = 424 1.67 hannken fstrans_alloc_lwp_info(fmi->fmi_lower_info->fmi_mount); 425 1.67 hannken if (fli_lower == NULL) { 426 1.67 hannken mutex_enter(&fstrans_lock); 427 1.67 hannken fstrans_mount_dtor(fmi); 428 1.67 hannken mutex_exit(&fstrans_lock); 429 1.67 hannken 430 1.67 hannken return NULL; 431 1.67 hannken } 432 1.67 hannken } else { 433 1.67 hannken fli_lower = NULL; 434 1.67 hannken } 435 1.67 hannken 436 1.67 hannken /* 437 1.63 ad * Allocate a new entry. 438 1.26 hannken */ 439 1.63 ad fli = pool_cache_get(fstrans_lwp_cache, PR_WAITOK); 440 1.63 ad KASSERT(fli->fli_trans_cnt == 0); 441 1.63 ad KASSERT(fli->fli_cow_cnt == 0); 442 1.63 ad KASSERT(fli->fli_alias_cnt == 0); 443 1.63 ad KASSERT(fli->fli_mount == NULL); 444 1.63 ad KASSERT(fli->fli_alias == NULL); 445 1.63 ad KASSERT(fli->fli_mountinfo == NULL); 446 1.63 ad KASSERT(fli->fli_self == NULL); 447 1.20 hannken 448 1.26 hannken /* 449 1.67 hannken * Attach the mount info and alias. 450 1.26 hannken */ 451 1.54 hannken 452 1.63 ad fli->fli_self = curlwp; 453 1.54 hannken fli->fli_mount = mp; 454 1.54 hannken fli->fli_mountinfo = fmi; 455 1.54 hannken 456 1.66 hannken fli->fli_succ = curlwp->l_fstrans; 457 1.66 hannken curlwp->l_fstrans = fli; 458 1.66 hannken 459 1.67 hannken if (fli_lower) { 460 1.67 hannken fli->fli_alias = fli_lower; 461 1.59 hannken fli->fli_alias->fli_alias_cnt++; 462 1.58 hannken fli = fli->fli_alias; 463 1.44 hannken } 464 1.26 hannken 465 1.26 hannken return fli; 466 1.26 hannken } 467 1.26 hannken 468 1.26 hannken /* 469 1.48 hannken * Retrieve the per lwp info for this mount allocating if necessary. 470 1.48 hannken */ 471 1.48 hannken static inline struct fstrans_lwp_info * 472 1.48 hannken fstrans_get_lwp_info(struct mount *mp, bool do_alloc) 473 1.48 hannken { 474 1.58 hannken struct fstrans_lwp_info *fli; 475 1.48 hannken 476 1.48 hannken /* 477 1.48 hannken * Scan our list for a match. 478 1.48 hannken */ 479 1.57 hannken for (fli = curlwp->l_fstrans; fli; fli = fli->fli_succ) { 480 1.54 hannken if (fli->fli_mount == mp) { 481 1.70 hannken KASSERT(mp->mnt_lower == NULL || 482 1.70 hannken fli->fli_alias != NULL); 483 1.58 hannken if (fli->fli_alias != NULL) 484 1.58 hannken fli = fli->fli_alias; 485 1.54 hannken break; 486 1.54 hannken } 487 1.54 hannken } 488 1.54 hannken 489 1.54 hannken if (do_alloc) { 490 1.54 hannken if (__predict_false(fli == NULL)) 491 1.54 hannken fli = fstrans_alloc_lwp_info(mp); 492 1.48 hannken } 493 1.48 hannken 494 1.54 hannken return fli; 495 1.48 hannken } 496 1.48 hannken 497 1.48 hannken /* 498 1.26 hannken * Check if this lock type is granted at this state. 499 1.26 hannken */ 500 1.26 hannken static bool 501 1.61 hannken grant_lock(const struct fstrans_mount_info *fmi, 502 1.61 hannken const enum fstrans_lock_type type) 503 1.26 hannken { 504 1.20 hannken 505 1.61 hannken if (__predict_true(fmi->fmi_state == FSTRANS_NORMAL)) 506 1.26 hannken return true; 507 1.61 hannken if (fmi->fmi_owner == curlwp) 508 1.26 hannken return true; 509 1.61 hannken if (fmi->fmi_state == FSTRANS_SUSPENDING && type == FSTRANS_LAZY) 510 1.51 hannken return true; 511 1.20 hannken 512 1.26 hannken return false; 513 1.20 hannken } 514 1.20 hannken 515 1.20 hannken /* 516 1.1 hannken * Start a transaction. If this thread already has a transaction on this 517 1.1 hannken * file system increment the reference counter. 518 1.1 hannken */ 519 1.46 hannken static inline int 520 1.1 hannken _fstrans_start(struct mount *mp, enum fstrans_lock_type lock_type, int wait) 521 1.1 hannken { 522 1.26 hannken int s; 523 1.20 hannken struct fstrans_lwp_info *fli; 524 1.1 hannken struct fstrans_mount_info *fmi; 525 1.1 hannken 526 1.18 yamt ASSERT_SLEEPABLE(); 527 1.1 hannken 528 1.54 hannken fli = fstrans_get_lwp_info(mp, true); 529 1.66 hannken if (fli == NULL) 530 1.66 hannken return 0; 531 1.54 hannken fmi = fli->fli_mountinfo; 532 1.1 hannken 533 1.20 hannken if (fli->fli_trans_cnt > 0) { 534 1.20 hannken fli->fli_trans_cnt += 1; 535 1.26 hannken 536 1.20 hannken return 0; 537 1.1 hannken } 538 1.1 hannken 539 1.26 hannken s = pserialize_read_enter(); 540 1.61 hannken if (__predict_true(grant_lock(fmi, lock_type))) { 541 1.26 hannken fli->fli_trans_cnt = 1; 542 1.26 hannken fli->fli_lock_type = lock_type; 543 1.26 hannken pserialize_read_exit(s); 544 1.1 hannken 545 1.26 hannken return 0; 546 1.26 hannken } 547 1.26 hannken pserialize_read_exit(s); 548 1.8 hannken 549 1.26 hannken if (! wait) 550 1.73 riastrad return SET_ERROR(EBUSY); 551 1.1 hannken 552 1.26 hannken mutex_enter(&fstrans_lock); 553 1.61 hannken while (! grant_lock(fmi, lock_type)) 554 1.26 hannken cv_wait(&fstrans_state_cv, &fstrans_lock); 555 1.20 hannken fli->fli_trans_cnt = 1; 556 1.20 hannken fli->fli_lock_type = lock_type; 557 1.26 hannken mutex_exit(&fstrans_lock); 558 1.1 hannken 559 1.1 hannken return 0; 560 1.1 hannken } 561 1.1 hannken 562 1.46 hannken void 563 1.46 hannken fstrans_start(struct mount *mp) 564 1.46 hannken { 565 1.46 hannken int error __diagused; 566 1.46 hannken 567 1.46 hannken error = _fstrans_start(mp, FSTRANS_SHARED, 1); 568 1.46 hannken KASSERT(error == 0); 569 1.46 hannken } 570 1.46 hannken 571 1.46 hannken int 572 1.46 hannken fstrans_start_nowait(struct mount *mp) 573 1.46 hannken { 574 1.46 hannken 575 1.46 hannken return _fstrans_start(mp, FSTRANS_SHARED, 0); 576 1.46 hannken } 577 1.46 hannken 578 1.51 hannken void 579 1.51 hannken fstrans_start_lazy(struct mount *mp) 580 1.51 hannken { 581 1.51 hannken int error __diagused; 582 1.51 hannken 583 1.51 hannken error = _fstrans_start(mp, FSTRANS_LAZY, 1); 584 1.51 hannken KASSERT(error == 0); 585 1.51 hannken } 586 1.51 hannken 587 1.1 hannken /* 588 1.1 hannken * Finish a transaction. 589 1.1 hannken */ 590 1.1 hannken void 591 1.1 hannken fstrans_done(struct mount *mp) 592 1.1 hannken { 593 1.26 hannken int s; 594 1.1 hannken struct fstrans_lwp_info *fli; 595 1.1 hannken struct fstrans_mount_info *fmi; 596 1.1 hannken 597 1.66 hannken fli = fstrans_get_lwp_info(mp, false); 598 1.66 hannken if (fli == NULL) 599 1.52 hannken return; 600 1.54 hannken fmi = fli->fli_mountinfo; 601 1.26 hannken KASSERT(fli->fli_trans_cnt > 0); 602 1.26 hannken 603 1.26 hannken if (fli->fli_trans_cnt > 1) { 604 1.26 hannken fli->fli_trans_cnt -= 1; 605 1.26 hannken 606 1.26 hannken return; 607 1.1 hannken } 608 1.1 hannken 609 1.56 hannken if (__predict_false(fstrans_gone_count > 0)) 610 1.56 hannken fstrans_clear_lwp_info(); 611 1.56 hannken 612 1.26 hannken s = pserialize_read_enter(); 613 1.26 hannken if (__predict_true(fmi->fmi_state == FSTRANS_NORMAL)) { 614 1.26 hannken fli->fli_trans_cnt = 0; 615 1.26 hannken pserialize_read_exit(s); 616 1.26 hannken 617 1.26 hannken return; 618 1.26 hannken } 619 1.26 hannken pserialize_read_exit(s); 620 1.20 hannken 621 1.26 hannken mutex_enter(&fstrans_lock); 622 1.26 hannken fli->fli_trans_cnt = 0; 623 1.26 hannken cv_signal(&fstrans_count_cv); 624 1.26 hannken mutex_exit(&fstrans_lock); 625 1.1 hannken } 626 1.1 hannken 627 1.1 hannken /* 628 1.62 hannken * Check if we hold an lock. 629 1.62 hannken */ 630 1.62 hannken int 631 1.62 hannken fstrans_held(struct mount *mp) 632 1.62 hannken { 633 1.62 hannken struct fstrans_lwp_info *fli; 634 1.62 hannken struct fstrans_mount_info *fmi; 635 1.62 hannken 636 1.62 hannken KASSERT(mp != dead_rootmount); 637 1.62 hannken 638 1.68 hannken fli = fstrans_get_lwp_info(mp, false); 639 1.66 hannken if (fli == NULL) 640 1.66 hannken return 0; 641 1.62 hannken fmi = fli->fli_mountinfo; 642 1.62 hannken 643 1.62 hannken return (fli->fli_trans_cnt > 0 || fmi->fmi_owner == curlwp); 644 1.62 hannken } 645 1.62 hannken 646 1.62 hannken /* 647 1.1 hannken * Check if this thread has an exclusive lock. 648 1.1 hannken */ 649 1.1 hannken int 650 1.1 hannken fstrans_is_owner(struct mount *mp) 651 1.1 hannken { 652 1.1 hannken struct fstrans_lwp_info *fli; 653 1.61 hannken struct fstrans_mount_info *fmi; 654 1.1 hannken 655 1.52 hannken KASSERT(mp != dead_rootmount); 656 1.52 hannken 657 1.68 hannken fli = fstrans_get_lwp_info(mp, false); 658 1.66 hannken if (fli == NULL) 659 1.66 hannken return 0; 660 1.61 hannken fmi = fli->fli_mountinfo; 661 1.1 hannken 662 1.61 hannken return (fmi->fmi_owner == curlwp); 663 1.1 hannken } 664 1.1 hannken 665 1.1 hannken /* 666 1.26 hannken * True, if no thread is in a transaction not granted at the current state. 667 1.26 hannken */ 668 1.26 hannken static bool 669 1.54 hannken state_change_done(const struct fstrans_mount_info *fmi) 670 1.26 hannken { 671 1.26 hannken struct fstrans_lwp_info *fli; 672 1.26 hannken 673 1.26 hannken KASSERT(mutex_owned(&fstrans_lock)); 674 1.26 hannken 675 1.26 hannken LIST_FOREACH(fli, &fstrans_fli_head, fli_list) { 676 1.54 hannken if (fli->fli_mountinfo != fmi) 677 1.26 hannken continue; 678 1.26 hannken if (fli->fli_trans_cnt == 0) 679 1.26 hannken continue; 680 1.61 hannken if (fli->fli_self == curlwp) 681 1.61 hannken continue; 682 1.61 hannken if (grant_lock(fmi, fli->fli_lock_type)) 683 1.26 hannken continue; 684 1.26 hannken 685 1.26 hannken return false; 686 1.26 hannken } 687 1.26 hannken 688 1.26 hannken return true; 689 1.26 hannken } 690 1.26 hannken 691 1.26 hannken /* 692 1.1 hannken * Set new file system state. 693 1.1 hannken */ 694 1.1 hannken int 695 1.1 hannken fstrans_setstate(struct mount *mp, enum fstrans_state new_state) 696 1.1 hannken { 697 1.26 hannken int error; 698 1.26 hannken enum fstrans_state old_state; 699 1.54 hannken struct fstrans_lwp_info *fli; 700 1.1 hannken struct fstrans_mount_info *fmi; 701 1.1 hannken 702 1.52 hannken KASSERT(mp != dead_rootmount); 703 1.52 hannken 704 1.54 hannken fli = fstrans_get_lwp_info(mp, true); 705 1.66 hannken if (fli == NULL) 706 1.73 riastrad return SET_ERROR(ENOENT); 707 1.54 hannken fmi = fli->fli_mountinfo; 708 1.26 hannken old_state = fmi->fmi_state; 709 1.26 hannken if (old_state == new_state) 710 1.26 hannken return 0; 711 1.1 hannken 712 1.26 hannken mutex_enter(&fstrans_lock); 713 1.26 hannken fmi->fmi_state = new_state; 714 1.26 hannken pserialize_perform(fstrans_psz); 715 1.26 hannken 716 1.26 hannken /* 717 1.26 hannken * All threads see the new state now. 718 1.26 hannken * Wait for transactions invalid at this state to leave. 719 1.26 hannken */ 720 1.26 hannken error = 0; 721 1.54 hannken while (! state_change_done(fmi)) { 722 1.50 manu error = cv_wait_sig(&fstrans_count_cv, &fstrans_lock); 723 1.26 hannken if (error) { 724 1.26 hannken new_state = fmi->fmi_state = FSTRANS_NORMAL; 725 1.26 hannken break; 726 1.26 hannken } 727 1.26 hannken } 728 1.61 hannken if (old_state != new_state) { 729 1.61 hannken if (old_state == FSTRANS_NORMAL) { 730 1.61 hannken KASSERT(fmi->fmi_owner == NULL); 731 1.61 hannken fmi->fmi_owner = curlwp; 732 1.61 hannken } 733 1.61 hannken if (new_state == FSTRANS_NORMAL) { 734 1.61 hannken KASSERT(fmi->fmi_owner == curlwp); 735 1.61 hannken fmi->fmi_owner = NULL; 736 1.61 hannken } 737 1.61 hannken } 738 1.26 hannken cv_broadcast(&fstrans_state_cv); 739 1.26 hannken mutex_exit(&fstrans_lock); 740 1.1 hannken 741 1.26 hannken return error; 742 1.1 hannken } 743 1.1 hannken 744 1.1 hannken /* 745 1.26 hannken * Get current file system state. 746 1.1 hannken */ 747 1.1 hannken enum fstrans_state 748 1.1 hannken fstrans_getstate(struct mount *mp) 749 1.1 hannken { 750 1.54 hannken struct fstrans_lwp_info *fli; 751 1.1 hannken struct fstrans_mount_info *fmi; 752 1.1 hannken 753 1.52 hannken KASSERT(mp != dead_rootmount); 754 1.52 hannken 755 1.54 hannken fli = fstrans_get_lwp_info(mp, true); 756 1.66 hannken KASSERT(fli != NULL); 757 1.54 hannken fmi = fli->fli_mountinfo; 758 1.1 hannken 759 1.1 hannken return fmi->fmi_state; 760 1.1 hannken } 761 1.1 hannken 762 1.1 hannken /* 763 1.1 hannken * Request a filesystem to suspend all operations. 764 1.1 hannken */ 765 1.1 hannken int 766 1.1 hannken vfs_suspend(struct mount *mp, int nowait) 767 1.1 hannken { 768 1.54 hannken struct fstrans_lwp_info *fli; 769 1.4 ad int error; 770 1.1 hannken 771 1.55 hannken if (mp == dead_rootmount) 772 1.73 riastrad return SET_ERROR(EOPNOTSUPP); 773 1.52 hannken 774 1.54 hannken fli = fstrans_get_lwp_info(mp, true); 775 1.66 hannken if (fli == NULL) 776 1.73 riastrad return SET_ERROR(ENOENT); 777 1.54 hannken 778 1.4 ad if (nowait) { 779 1.4 ad if (!mutex_tryenter(&vfs_suspend_lock)) 780 1.73 riastrad return SET_ERROR(EWOULDBLOCK); 781 1.4 ad } else 782 1.4 ad mutex_enter(&vfs_suspend_lock); 783 1.1 hannken 784 1.65 hannken if ((error = VFS_SUSPENDCTL(fli->fli_mount, SUSPEND_SUSPEND)) != 0) { 785 1.4 ad mutex_exit(&vfs_suspend_lock); 786 1.65 hannken return error; 787 1.65 hannken } 788 1.65 hannken 789 1.65 hannken if ((mp->mnt_iflag & IMNT_GONE) != 0) { 790 1.65 hannken vfs_resume(mp); 791 1.73 riastrad return SET_ERROR(ENOENT); 792 1.65 hannken } 793 1.1 hannken 794 1.65 hannken return 0; 795 1.1 hannken } 796 1.1 hannken 797 1.1 hannken /* 798 1.1 hannken * Request a filesystem to resume all operations. 799 1.1 hannken */ 800 1.1 hannken void 801 1.1 hannken vfs_resume(struct mount *mp) 802 1.1 hannken { 803 1.54 hannken struct fstrans_lwp_info *fli; 804 1.1 hannken 805 1.52 hannken KASSERT(mp != dead_rootmount); 806 1.52 hannken 807 1.54 hannken fli = fstrans_get_lwp_info(mp, false); 808 1.54 hannken mp = fli->fli_mount; 809 1.54 hannken 810 1.1 hannken VFS_SUSPENDCTL(mp, SUSPEND_RESUME); 811 1.4 ad mutex_exit(&vfs_suspend_lock); 812 1.1 hannken } 813 1.1 hannken 814 1.26 hannken /* 815 1.26 hannken * True, if no thread is running a cow handler. 816 1.26 hannken */ 817 1.26 hannken static bool 818 1.54 hannken cow_state_change_done(const struct fstrans_mount_info *fmi) 819 1.1 hannken { 820 1.1 hannken struct fstrans_lwp_info *fli; 821 1.1 hannken 822 1.26 hannken KASSERT(mutex_owned(&fstrans_lock)); 823 1.26 hannken KASSERT(fmi->fmi_cow_change); 824 1.26 hannken 825 1.26 hannken LIST_FOREACH(fli, &fstrans_fli_head, fli_list) { 826 1.54 hannken if (fli->fli_mount != fmi->fmi_mount) 827 1.26 hannken continue; 828 1.26 hannken if (fli->fli_cow_cnt == 0) 829 1.1 hannken continue; 830 1.26 hannken 831 1.26 hannken return false; 832 1.1 hannken } 833 1.26 hannken 834 1.26 hannken return true; 835 1.1 hannken } 836 1.1 hannken 837 1.26 hannken /* 838 1.26 hannken * Prepare for changing this mounts cow list. 839 1.26 hannken * Returns with fstrans_lock locked. 840 1.26 hannken */ 841 1.1 hannken static void 842 1.54 hannken cow_change_enter(struct fstrans_mount_info *fmi) 843 1.1 hannken { 844 1.1 hannken 845 1.26 hannken mutex_enter(&fstrans_lock); 846 1.26 hannken 847 1.26 hannken /* 848 1.26 hannken * Wait for other threads changing the list. 849 1.26 hannken */ 850 1.26 hannken while (fmi->fmi_cow_change) 851 1.26 hannken cv_wait(&fstrans_state_cv, &fstrans_lock); 852 1.26 hannken 853 1.26 hannken /* 854 1.26 hannken * Wait until all threads are aware of a state change. 855 1.26 hannken */ 856 1.26 hannken fmi->fmi_cow_change = true; 857 1.26 hannken pserialize_perform(fstrans_psz); 858 1.26 hannken 859 1.54 hannken while (! cow_state_change_done(fmi)) 860 1.26 hannken cv_wait(&fstrans_count_cv, &fstrans_lock); 861 1.1 hannken } 862 1.1 hannken 863 1.26 hannken /* 864 1.26 hannken * Done changing this mounts cow list. 865 1.26 hannken */ 866 1.26 hannken static void 867 1.54 hannken cow_change_done(struct fstrans_mount_info *fmi) 868 1.1 hannken { 869 1.26 hannken 870 1.26 hannken KASSERT(mutex_owned(&fstrans_lock)); 871 1.26 hannken 872 1.26 hannken fmi->fmi_cow_change = false; 873 1.26 hannken pserialize_perform(fstrans_psz); 874 1.1 hannken 875 1.26 hannken cv_broadcast(&fstrans_state_cv); 876 1.1 hannken 877 1.26 hannken mutex_exit(&fstrans_lock); 878 1.1 hannken } 879 1.12 hannken 880 1.26 hannken /* 881 1.26 hannken * Add a handler to this mount. 882 1.26 hannken */ 883 1.12 hannken int 884 1.15 hannken fscow_establish(struct mount *mp, int (*func)(void *, struct buf *, bool), 885 1.15 hannken void *arg) 886 1.12 hannken { 887 1.16 ad struct fstrans_mount_info *fmi; 888 1.31 matt struct fscow_handler *newch; 889 1.12 hannken 890 1.52 hannken KASSERT(mp != dead_rootmount); 891 1.16 ad 892 1.63 ad mutex_enter(&fstrans_lock); 893 1.66 hannken fmi = fstrans_mount_get(mp); 894 1.26 hannken KASSERT(fmi != NULL); 895 1.53 hannken fmi->fmi_ref_cnt += 1; 896 1.63 ad mutex_exit(&fstrans_lock); 897 1.12 hannken 898 1.32 pooka newch = kmem_alloc(sizeof(*newch), KM_SLEEP); 899 1.31 matt newch->ch_func = func; 900 1.31 matt newch->ch_arg = arg; 901 1.26 hannken 902 1.54 hannken cow_change_enter(fmi); 903 1.31 matt LIST_INSERT_HEAD(&fmi->fmi_cow_handler, newch, ch_list); 904 1.54 hannken cow_change_done(fmi); 905 1.12 hannken 906 1.12 hannken return 0; 907 1.12 hannken } 908 1.12 hannken 909 1.26 hannken /* 910 1.26 hannken * Remove a handler from this mount. 911 1.26 hannken */ 912 1.12 hannken int 913 1.15 hannken fscow_disestablish(struct mount *mp, int (*func)(void *, struct buf *, bool), 914 1.12 hannken void *arg) 915 1.12 hannken { 916 1.16 ad struct fstrans_mount_info *fmi; 917 1.12 hannken struct fscow_handler *hp = NULL; 918 1.12 hannken 919 1.52 hannken KASSERT(mp != dead_rootmount); 920 1.12 hannken 921 1.66 hannken mutex_enter(&fstrans_lock); 922 1.66 hannken fmi = fstrans_mount_get(mp); 923 1.26 hannken KASSERT(fmi != NULL); 924 1.66 hannken mutex_exit(&fstrans_lock); 925 1.16 ad 926 1.54 hannken cow_change_enter(fmi); 927 1.26 hannken LIST_FOREACH(hp, &fmi->fmi_cow_handler, ch_list) 928 1.12 hannken if (hp->ch_func == func && hp->ch_arg == arg) 929 1.12 hannken break; 930 1.12 hannken if (hp != NULL) { 931 1.26 hannken LIST_REMOVE(hp, ch_list); 932 1.12 hannken kmem_free(hp, sizeof(*hp)); 933 1.12 hannken } 934 1.63 ad fstrans_mount_dtor(fmi); 935 1.54 hannken cow_change_done(fmi); 936 1.12 hannken 937 1.73 riastrad return hp ? 0 : SET_ERROR(EINVAL); 938 1.12 hannken } 939 1.12 hannken 940 1.26 hannken /* 941 1.26 hannken * Check for need to copy block that is about to be written. 942 1.26 hannken */ 943 1.12 hannken int 944 1.15 hannken fscow_run(struct buf *bp, bool data_valid) 945 1.12 hannken { 946 1.26 hannken int error, s; 947 1.12 hannken struct mount *mp; 948 1.20 hannken struct fstrans_lwp_info *fli; 949 1.16 ad struct fstrans_mount_info *fmi; 950 1.12 hannken struct fscow_handler *hp; 951 1.12 hannken 952 1.26 hannken /* 953 1.26 hannken * First check if we need run the copy-on-write handler. 954 1.26 hannken */ 955 1.17 hannken if ((bp->b_flags & B_COWDONE)) 956 1.26 hannken return 0; 957 1.26 hannken if (bp->b_vp == NULL) { 958 1.26 hannken bp->b_flags |= B_COWDONE; 959 1.26 hannken return 0; 960 1.26 hannken } 961 1.12 hannken if (bp->b_vp->v_type == VBLK) 962 1.27 hannken mp = spec_node_getmountedfs(bp->b_vp); 963 1.12 hannken else 964 1.12 hannken mp = bp->b_vp->v_mount; 965 1.52 hannken if (mp == NULL || mp == dead_rootmount) { 966 1.26 hannken bp->b_flags |= B_COWDONE; 967 1.26 hannken return 0; 968 1.26 hannken } 969 1.12 hannken 970 1.26 hannken fli = fstrans_get_lwp_info(mp, true); 971 1.66 hannken KASSERT(fli != NULL); 972 1.54 hannken fmi = fli->fli_mountinfo; 973 1.12 hannken 974 1.26 hannken /* 975 1.26 hannken * On non-recursed run check if other threads 976 1.26 hannken * want to change the list. 977 1.26 hannken */ 978 1.26 hannken if (fli->fli_cow_cnt == 0) { 979 1.26 hannken s = pserialize_read_enter(); 980 1.26 hannken if (__predict_false(fmi->fmi_cow_change)) { 981 1.26 hannken pserialize_read_exit(s); 982 1.26 hannken mutex_enter(&fstrans_lock); 983 1.26 hannken while (fmi->fmi_cow_change) 984 1.26 hannken cv_wait(&fstrans_state_cv, &fstrans_lock); 985 1.26 hannken fli->fli_cow_cnt = 1; 986 1.26 hannken mutex_exit(&fstrans_lock); 987 1.26 hannken } else { 988 1.26 hannken fli->fli_cow_cnt = 1; 989 1.26 hannken pserialize_read_exit(s); 990 1.26 hannken } 991 1.26 hannken } else 992 1.26 hannken fli->fli_cow_cnt += 1; 993 1.20 hannken 994 1.26 hannken /* 995 1.26 hannken * Run all copy-on-write handlers, stop on error. 996 1.26 hannken */ 997 1.26 hannken error = 0; 998 1.26 hannken LIST_FOREACH(hp, &fmi->fmi_cow_handler, ch_list) 999 1.15 hannken if ((error = (*hp->ch_func)(hp->ch_arg, bp, data_valid)) != 0) 1000 1.12 hannken break; 1001 1.72 riastrad if (error == 0) 1002 1.72 riastrad bp->b_flags |= B_COWDONE; 1003 1.15 hannken 1004 1.26 hannken /* 1005 1.26 hannken * Check if other threads want to change the list. 1006 1.26 hannken */ 1007 1.26 hannken if (fli->fli_cow_cnt > 1) { 1008 1.26 hannken fli->fli_cow_cnt -= 1; 1009 1.26 hannken } else { 1010 1.26 hannken s = pserialize_read_enter(); 1011 1.26 hannken if (__predict_false(fmi->fmi_cow_change)) { 1012 1.26 hannken pserialize_read_exit(s); 1013 1.26 hannken mutex_enter(&fstrans_lock); 1014 1.26 hannken fli->fli_cow_cnt = 0; 1015 1.26 hannken cv_signal(&fstrans_count_cv); 1016 1.26 hannken mutex_exit(&fstrans_lock); 1017 1.26 hannken } else { 1018 1.26 hannken fli->fli_cow_cnt = 0; 1019 1.26 hannken pserialize_read_exit(s); 1020 1.26 hannken } 1021 1.26 hannken } 1022 1.26 hannken 1023 1.12 hannken return error; 1024 1.12 hannken } 1025 1.26 hannken 1026 1.26 hannken #if defined(DDB) 1027 1.26 hannken void fstrans_dump(int); 1028 1.26 hannken 1029 1.26 hannken static void 1030 1.26 hannken fstrans_print_lwp(struct proc *p, struct lwp *l, int verbose) 1031 1.26 hannken { 1032 1.26 hannken char prefix[9]; 1033 1.26 hannken struct fstrans_lwp_info *fli; 1034 1.26 hannken 1035 1.26 hannken snprintf(prefix, sizeof(prefix), "%d.%d", p->p_pid, l->l_lid); 1036 1.26 hannken LIST_FOREACH(fli, &fstrans_fli_head, fli_list) { 1037 1.26 hannken if (fli->fli_self != l) 1038 1.26 hannken continue; 1039 1.26 hannken if (fli->fli_trans_cnt == 0 && fli->fli_cow_cnt == 0) { 1040 1.26 hannken if (! verbose) 1041 1.26 hannken continue; 1042 1.26 hannken } 1043 1.26 hannken printf("%-8s", prefix); 1044 1.26 hannken if (verbose) 1045 1.26 hannken printf(" @%p", fli); 1046 1.54 hannken if (fli->fli_mount == dead_rootmount) 1047 1.54 hannken printf(" <dead>"); 1048 1.54 hannken else if (fli->fli_mount != NULL) 1049 1.26 hannken printf(" (%s)", fli->fli_mount->mnt_stat.f_mntonname); 1050 1.26 hannken else 1051 1.26 hannken printf(" NULL"); 1052 1.58 hannken if (fli->fli_alias != NULL) { 1053 1.58 hannken struct mount *amp = fli->fli_alias->fli_mount; 1054 1.58 hannken 1055 1.58 hannken printf(" alias"); 1056 1.58 hannken if (verbose) 1057 1.58 hannken printf(" @%p", fli->fli_alias); 1058 1.58 hannken if (amp == NULL) 1059 1.58 hannken printf(" NULL"); 1060 1.58 hannken else 1061 1.58 hannken printf(" (%s)", amp->mnt_stat.f_mntonname); 1062 1.58 hannken } 1063 1.54 hannken if (fli->fli_mountinfo && fli->fli_mountinfo->fmi_gone) 1064 1.54 hannken printf(" gone"); 1065 1.26 hannken if (fli->fli_trans_cnt == 0) { 1066 1.26 hannken printf(" -"); 1067 1.26 hannken } else { 1068 1.26 hannken switch (fli->fli_lock_type) { 1069 1.51 hannken case FSTRANS_LAZY: 1070 1.51 hannken printf(" lazy"); 1071 1.51 hannken break; 1072 1.26 hannken case FSTRANS_SHARED: 1073 1.26 hannken printf(" shared"); 1074 1.26 hannken break; 1075 1.26 hannken default: 1076 1.26 hannken printf(" %#x", fli->fli_lock_type); 1077 1.26 hannken break; 1078 1.26 hannken } 1079 1.26 hannken } 1080 1.59 hannken printf(" %d cow %d alias %d\n", 1081 1.59 hannken fli->fli_trans_cnt, fli->fli_cow_cnt, fli->fli_alias_cnt); 1082 1.26 hannken prefix[0] = '\0'; 1083 1.26 hannken } 1084 1.26 hannken } 1085 1.26 hannken 1086 1.26 hannken static void 1087 1.26 hannken fstrans_print_mount(struct mount *mp, int verbose) 1088 1.26 hannken { 1089 1.66 hannken uint32_t indx; 1090 1.26 hannken struct fstrans_mount_info *fmi; 1091 1.26 hannken 1092 1.66 hannken indx = fstrans_mount_hash(mp); 1093 1.66 hannken SLIST_FOREACH(fmi, &fstrans_mount_hashtab[indx], fmi_hash) 1094 1.66 hannken if (fmi->fmi_mount == mp) 1095 1.66 hannken break; 1096 1.66 hannken 1097 1.26 hannken if (!verbose && (fmi == NULL || fmi->fmi_state == FSTRANS_NORMAL)) 1098 1.26 hannken return; 1099 1.26 hannken 1100 1.26 hannken printf("%-16s ", mp->mnt_stat.f_mntonname); 1101 1.26 hannken if (fmi == NULL) { 1102 1.26 hannken printf("(null)\n"); 1103 1.26 hannken return; 1104 1.26 hannken } 1105 1.61 hannken printf("owner %p ", fmi->fmi_owner); 1106 1.26 hannken switch (fmi->fmi_state) { 1107 1.26 hannken case FSTRANS_NORMAL: 1108 1.26 hannken printf("state normal\n"); 1109 1.26 hannken break; 1110 1.51 hannken case FSTRANS_SUSPENDING: 1111 1.51 hannken printf("state suspending\n"); 1112 1.51 hannken break; 1113 1.26 hannken case FSTRANS_SUSPENDED: 1114 1.26 hannken printf("state suspended\n"); 1115 1.26 hannken break; 1116 1.26 hannken default: 1117 1.26 hannken printf("state %#x\n", fmi->fmi_state); 1118 1.26 hannken break; 1119 1.26 hannken } 1120 1.26 hannken } 1121 1.26 hannken 1122 1.26 hannken void 1123 1.26 hannken fstrans_dump(int full) 1124 1.26 hannken { 1125 1.26 hannken const struct proclist_desc *pd; 1126 1.26 hannken struct proc *p; 1127 1.26 hannken struct lwp *l; 1128 1.26 hannken struct mount *mp; 1129 1.26 hannken 1130 1.26 hannken printf("Fstrans locks by lwp:\n"); 1131 1.26 hannken for (pd = proclists; pd->pd_list != NULL; pd++) 1132 1.26 hannken PROCLIST_FOREACH(p, pd->pd_list) 1133 1.26 hannken LIST_FOREACH(l, &p->p_lwps, l_sibling) 1134 1.26 hannken fstrans_print_lwp(p, l, full == 1); 1135 1.26 hannken 1136 1.26 hannken printf("Fstrans state by mount:\n"); 1137 1.41 hannken for (mp = _mountlist_next(NULL); mp; mp = _mountlist_next(mp)) 1138 1.26 hannken fstrans_print_mount(mp, full == 1); 1139 1.26 hannken } 1140 1.26 hannken #endif /* defined(DDB) */ 1141