Home | History | Annotate | Line # | Download | only in kern
vfs_trans.c revision 1.70.8.1
      1  1.70.8.1  perseant /*	$NetBSD: vfs_trans.c,v 1.70.8.1 2025/08/02 05:57:44 perseant 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.70.8.1  perseant __KERNEL_RCSID(0, "$NetBSD: vfs_trans.c,v 1.70.8.1 2025/08/02 05:57:44 perseant 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.70.8.1  perseant #include <sys/types.h>
     45  1.70.8.1  perseant 
     46      1.26   hannken #include <sys/atomic.h>
     47      1.24     pooka #include <sys/buf.h>
     48  1.70.8.1  perseant #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.70.8.1  perseant #include <sys/pool.h>
     53  1.70.8.1  perseant #include <sys/proc.h>
     54      1.26   hannken #include <sys/pserialize.h>
     55  1.70.8.1  perseant #include <sys/sdt.h>
     56  1.70.8.1  perseant #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.70.8.1  perseant 		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.70.8.1  perseant 		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.70.8.1  perseant 		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.70.8.1  perseant 		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.70.8.1  perseant 			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.70.8.1  perseant 		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.70.8.1  perseant 	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.70.8.1  perseant 	if (error == 0)
   1002  1.70.8.1  perseant 		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