17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 520a1ae8aSjkennedy * Common Development and Distribution License (the "License"). 620a1ae8aSjkennedy * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 2280d34432Sfrankho * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 24*b97d6ca7SMilan Jurik * Copyright 2012 Milan Jurik. All rights reserved. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #include <sys/systm.h> 287c478bd9Sstevel@tonic-gate #include <sys/types.h> 297c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 307c478bd9Sstevel@tonic-gate #include <sys/errno.h> 317c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 327c478bd9Sstevel@tonic-gate #include <sys/debug.h> 337c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 347c478bd9Sstevel@tonic-gate #include <sys/conf.h> 357c478bd9Sstevel@tonic-gate #include <sys/proc.h> 367c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 377c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_inode.h> 387c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_filio.h> 397c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_log.h> 407c478bd9Sstevel@tonic-gate #include <sys/inttypes.h> 417c478bd9Sstevel@tonic-gate #include <sys/atomic.h> 427c478bd9Sstevel@tonic-gate #include <sys/tuneable.h> 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate /* 457c478bd9Sstevel@tonic-gate * externs 467c478bd9Sstevel@tonic-gate */ 477c478bd9Sstevel@tonic-gate extern pri_t minclsyspri; 487c478bd9Sstevel@tonic-gate extern struct kmem_cache *lufs_bp; 49*b97d6ca7SMilan Jurik extern int ufs_trans_push_quota(ufsvfs_t *, delta_t, struct dquot *); 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate /* 527c478bd9Sstevel@tonic-gate * globals 537c478bd9Sstevel@tonic-gate */ 547c478bd9Sstevel@tonic-gate kmem_cache_t *mapentry_cache; 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate /* 577c478bd9Sstevel@tonic-gate * logmap tuning constants 587c478bd9Sstevel@tonic-gate */ 597c478bd9Sstevel@tonic-gate long logmap_maxnme_commit = 2048; 607c478bd9Sstevel@tonic-gate long logmap_maxnme_async = 4096; 617c478bd9Sstevel@tonic-gate long logmap_maxnme_sync = 6144; 627c478bd9Sstevel@tonic-gate long logmap_maxcfrag_commit = 4; /* Max canceled fragments per moby */ 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate uint64_t ufs_crb_size = 0; /* current size of all crb buffers */ 667c478bd9Sstevel@tonic-gate uint64_t ufs_crb_max_size = 0; /* highest crb buffer use so far */ 677c478bd9Sstevel@tonic-gate size_t ufs_crb_limit; /* max allowable size for crbs */ 687c478bd9Sstevel@tonic-gate uint64_t ufs_crb_alloc_fails = 0; /* crb allocation failures stat */ 697c478bd9Sstevel@tonic-gate #define UFS_MAX_CRB_DEFAULT_DIVISOR 10 /* max 1/10 kmem_maxavail() */ 707c478bd9Sstevel@tonic-gate int ufs_max_crb_divisor = UFS_MAX_CRB_DEFAULT_DIVISOR; /* tunable */ 717c478bd9Sstevel@tonic-gate void handle_dquot(mapentry_t *); 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate /* 747c478bd9Sstevel@tonic-gate * GENERIC MAP ROUTINES 757c478bd9Sstevel@tonic-gate */ 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate #define CRB_FREE(crb, me) \ 787c478bd9Sstevel@tonic-gate kmem_free(crb->c_buf, crb->c_nb); \ 797c478bd9Sstevel@tonic-gate atomic_add_64(&ufs_crb_size, -(uint64_t)crb->c_nb); \ 807c478bd9Sstevel@tonic-gate kmem_free(crb, sizeof (crb_t)); \ 817c478bd9Sstevel@tonic-gate (me)->me_crb = NULL; 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate #define CRB_RELE(me) { \ 847c478bd9Sstevel@tonic-gate crb_t *crb = (me)->me_crb; \ 857c478bd9Sstevel@tonic-gate if (crb && (--crb->c_refcnt == 0)) { \ 867c478bd9Sstevel@tonic-gate CRB_FREE(crb, me) \ 877c478bd9Sstevel@tonic-gate } \ 887c478bd9Sstevel@tonic-gate } 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate /* 917c478bd9Sstevel@tonic-gate * Check that the old delta has an argument and a push function of 927c478bd9Sstevel@tonic-gate * ufs_trans_push_quota(), then check that the old and new deltas differ. 937c478bd9Sstevel@tonic-gate * If so we clean up with handle_dquot() before replacing the old delta. 947c478bd9Sstevel@tonic-gate */ 957c478bd9Sstevel@tonic-gate #define HANDLE_DQUOT(me, melist) { \ 967c478bd9Sstevel@tonic-gate if ((me->me_arg) && \ 977c478bd9Sstevel@tonic-gate (me->me_func == ufs_trans_push_quota)) { \ 987c478bd9Sstevel@tonic-gate if (!((me->me_dt == melist->me_dt) && \ 997c478bd9Sstevel@tonic-gate (me->me_arg == melist->me_arg) && \ 1007c478bd9Sstevel@tonic-gate (me->me_func == melist->me_func))) { \ 1017c478bd9Sstevel@tonic-gate handle_dquot(me); \ 1027c478bd9Sstevel@tonic-gate } \ 1037c478bd9Sstevel@tonic-gate } \ 1047c478bd9Sstevel@tonic-gate } 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate /* 1077c478bd9Sstevel@tonic-gate * free up all the mapentries for a map 1087c478bd9Sstevel@tonic-gate */ 1097c478bd9Sstevel@tonic-gate void 1107c478bd9Sstevel@tonic-gate map_free_entries(mt_map_t *mtm) 1117c478bd9Sstevel@tonic-gate { 1127c478bd9Sstevel@tonic-gate int i; 1137c478bd9Sstevel@tonic-gate mapentry_t *me; 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate while ((me = mtm->mtm_next) != (mapentry_t *)mtm) { 1167c478bd9Sstevel@tonic-gate me->me_next->me_prev = me->me_prev; 1177c478bd9Sstevel@tonic-gate me->me_prev->me_next = me->me_next; 1187c478bd9Sstevel@tonic-gate CRB_RELE(me); 1197c478bd9Sstevel@tonic-gate kmem_cache_free(mapentry_cache, me); 1207c478bd9Sstevel@tonic-gate } 1217c478bd9Sstevel@tonic-gate for (i = 0; i < mtm->mtm_nhash; i++) 1227c478bd9Sstevel@tonic-gate mtm->mtm_hash[i] = NULL; 1237c478bd9Sstevel@tonic-gate mtm->mtm_nme = 0; 1247c478bd9Sstevel@tonic-gate mtm->mtm_nmet = 0; 1257c478bd9Sstevel@tonic-gate } 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate /* 1287c478bd9Sstevel@tonic-gate * done with map; free if necessary 1297c478bd9Sstevel@tonic-gate */ 1307c478bd9Sstevel@tonic-gate mt_map_t * 1317c478bd9Sstevel@tonic-gate map_put(mt_map_t *mtm) 1327c478bd9Sstevel@tonic-gate { 1337c478bd9Sstevel@tonic-gate /* 1347c478bd9Sstevel@tonic-gate * free up the map's memory 1357c478bd9Sstevel@tonic-gate */ 1367c478bd9Sstevel@tonic-gate map_free_entries(mtm); 1377c478bd9Sstevel@tonic-gate ASSERT(map_put_debug(mtm)); 1387c478bd9Sstevel@tonic-gate kmem_free(mtm->mtm_hash, 1397c478bd9Sstevel@tonic-gate (size_t) (sizeof (mapentry_t *) * mtm->mtm_nhash)); 1407c478bd9Sstevel@tonic-gate mutex_destroy(&mtm->mtm_mutex); 1417c478bd9Sstevel@tonic-gate mutex_destroy(&mtm->mtm_scan_mutex); 1427c478bd9Sstevel@tonic-gate cv_destroy(&mtm->mtm_to_roll_cv); 1437c478bd9Sstevel@tonic-gate cv_destroy(&mtm->mtm_from_roll_cv); 1447c478bd9Sstevel@tonic-gate rw_destroy(&mtm->mtm_rwlock); 1457c478bd9Sstevel@tonic-gate mutex_destroy(&mtm->mtm_lock); 1467c478bd9Sstevel@tonic-gate cv_destroy(&mtm->mtm_cv_commit); 1477c478bd9Sstevel@tonic-gate cv_destroy(&mtm->mtm_cv_next); 1487c478bd9Sstevel@tonic-gate cv_destroy(&mtm->mtm_cv_eot); 1497c478bd9Sstevel@tonic-gate cv_destroy(&mtm->mtm_cv); 1507c478bd9Sstevel@tonic-gate kmem_free(mtm, sizeof (mt_map_t)); 1517c478bd9Sstevel@tonic-gate return (NULL); 1527c478bd9Sstevel@tonic-gate } 1537c478bd9Sstevel@tonic-gate /* 1547c478bd9Sstevel@tonic-gate * Allocate a map; 1557c478bd9Sstevel@tonic-gate */ 1567c478bd9Sstevel@tonic-gate mt_map_t * 1577c478bd9Sstevel@tonic-gate map_get(ml_unit_t *ul, enum maptypes maptype, int nh) 1587c478bd9Sstevel@tonic-gate { 1597c478bd9Sstevel@tonic-gate mt_map_t *mtm; 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate /* 1627c478bd9Sstevel@tonic-gate * assume the map is not here and allocate the necessary structs 1637c478bd9Sstevel@tonic-gate */ 1647c478bd9Sstevel@tonic-gate mtm = kmem_zalloc(sizeof (mt_map_t), KM_SLEEP); 1657c478bd9Sstevel@tonic-gate mutex_init(&mtm->mtm_mutex, NULL, MUTEX_DEFAULT, NULL); 1667c478bd9Sstevel@tonic-gate mutex_init(&mtm->mtm_scan_mutex, NULL, MUTEX_DEFAULT, NULL); 1677c478bd9Sstevel@tonic-gate cv_init(&mtm->mtm_to_roll_cv, NULL, CV_DEFAULT, NULL); 1687c478bd9Sstevel@tonic-gate cv_init(&mtm->mtm_from_roll_cv, NULL, CV_DEFAULT, NULL); 1697c478bd9Sstevel@tonic-gate rw_init(&mtm->mtm_rwlock, NULL, RW_DEFAULT, NULL); 1707c478bd9Sstevel@tonic-gate mtm->mtm_next = (mapentry_t *)mtm; 1717c478bd9Sstevel@tonic-gate mtm->mtm_prev = (mapentry_t *)mtm; 1727c478bd9Sstevel@tonic-gate mtm->mtm_hash = kmem_zalloc((size_t) (sizeof (mapentry_t *) * nh), 1737c478bd9Sstevel@tonic-gate KM_SLEEP); 1747c478bd9Sstevel@tonic-gate mtm->mtm_nhash = nh; 1757c478bd9Sstevel@tonic-gate mtm->mtm_debug = ul->un_debug; 1767c478bd9Sstevel@tonic-gate mtm->mtm_type = maptype; 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate mtm->mtm_cfrags = 0; 1797c478bd9Sstevel@tonic-gate mtm->mtm_cfragmax = logmap_maxcfrag_commit; 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate /* 1827c478bd9Sstevel@tonic-gate * for scan test 1837c478bd9Sstevel@tonic-gate */ 1847c478bd9Sstevel@tonic-gate mtm->mtm_ul = ul; 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate /* 1877c478bd9Sstevel@tonic-gate * Initialize locks 1887c478bd9Sstevel@tonic-gate */ 1897c478bd9Sstevel@tonic-gate mutex_init(&mtm->mtm_lock, NULL, MUTEX_DEFAULT, NULL); 1907c478bd9Sstevel@tonic-gate cv_init(&mtm->mtm_cv_commit, NULL, CV_DEFAULT, NULL); 1917c478bd9Sstevel@tonic-gate cv_init(&mtm->mtm_cv_next, NULL, CV_DEFAULT, NULL); 1927c478bd9Sstevel@tonic-gate cv_init(&mtm->mtm_cv_eot, NULL, CV_DEFAULT, NULL); 1937c478bd9Sstevel@tonic-gate cv_init(&mtm->mtm_cv, NULL, CV_DEFAULT, NULL); 1947c478bd9Sstevel@tonic-gate ASSERT(map_get_debug(ul, mtm)); 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate return (mtm); 1977c478bd9Sstevel@tonic-gate } 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate /* 2007c478bd9Sstevel@tonic-gate * DELTAMAP ROUTINES 2017c478bd9Sstevel@tonic-gate */ 2027c478bd9Sstevel@tonic-gate /* 2037c478bd9Sstevel@tonic-gate * deltamap tuning constants 2047c478bd9Sstevel@tonic-gate */ 2057c478bd9Sstevel@tonic-gate long deltamap_maxnme = 1024; /* global so it can be set */ 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate int 2087c478bd9Sstevel@tonic-gate deltamap_need_commit(mt_map_t *mtm) 2097c478bd9Sstevel@tonic-gate { 2107c478bd9Sstevel@tonic-gate return (mtm->mtm_nme > deltamap_maxnme); 2117c478bd9Sstevel@tonic-gate } 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate /* 2147c478bd9Sstevel@tonic-gate * put a delta into a deltamap; may sleep on memory 2157c478bd9Sstevel@tonic-gate */ 2167c478bd9Sstevel@tonic-gate void 2177c478bd9Sstevel@tonic-gate deltamap_add( 2187c478bd9Sstevel@tonic-gate mt_map_t *mtm, 2197c478bd9Sstevel@tonic-gate offset_t mof, 2207c478bd9Sstevel@tonic-gate off_t nb, 2217c478bd9Sstevel@tonic-gate delta_t dtyp, 2227c478bd9Sstevel@tonic-gate int (*func)(), 2237c478bd9Sstevel@tonic-gate ulong_t arg, 2247c478bd9Sstevel@tonic-gate threadtrans_t *tp) 2257c478bd9Sstevel@tonic-gate { 2267c478bd9Sstevel@tonic-gate int32_t hnb; 2277c478bd9Sstevel@tonic-gate mapentry_t *me; 2287c478bd9Sstevel@tonic-gate mapentry_t **mep; 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate ASSERT(((mtm->mtm_debug & MT_CHECK_MAP) == 0) || 2317c478bd9Sstevel@tonic-gate map_check_linkage(mtm)); 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate mutex_enter(&mtm->mtm_mutex); 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate for (hnb = 0; nb; nb -= hnb, mof += hnb) { 2367c478bd9Sstevel@tonic-gate hnb = MAPBLOCKSIZE - (mof & MAPBLOCKOFF); 2377c478bd9Sstevel@tonic-gate if (hnb > nb) 2387c478bd9Sstevel@tonic-gate hnb = nb; 2397c478bd9Sstevel@tonic-gate /* 2407c478bd9Sstevel@tonic-gate * Search for dup entry. We need to ensure that we don't 2417c478bd9Sstevel@tonic-gate * replace a map entry which carries quota information 2427c478bd9Sstevel@tonic-gate * with a map entry which doesn't. In that case we lose 2437c478bd9Sstevel@tonic-gate * reference the the dquot structure which will not be 2447c478bd9Sstevel@tonic-gate * cleaned up by the push function me->me_func as this will 2457c478bd9Sstevel@tonic-gate * never be called. 2467c478bd9Sstevel@tonic-gate * The stray dquot would be found later by invalidatedq() 2477c478bd9Sstevel@tonic-gate * causing a panic when the filesystem is unmounted. 2487c478bd9Sstevel@tonic-gate */ 2497c478bd9Sstevel@tonic-gate mep = MAP_HASH(mof, mtm); 2507c478bd9Sstevel@tonic-gate for (me = *mep; me; me = me->me_hash) { 2517c478bd9Sstevel@tonic-gate if (DATAwithinME(mof, hnb, me)) { 2527c478bd9Sstevel@tonic-gate /* 2537c478bd9Sstevel@tonic-gate * Don't remove quota entries which have 2547c478bd9Sstevel@tonic-gate * incremented the ref count (those with a 2557c478bd9Sstevel@tonic-gate * ufs_trans_push_quota push function). 2567c478bd9Sstevel@tonic-gate * Let logmap_add[_buf] clean them up. 2577c478bd9Sstevel@tonic-gate */ 25880d34432Sfrankho if (me->me_func == ufs_trans_push_quota) { 2597c478bd9Sstevel@tonic-gate continue; 2607c478bd9Sstevel@tonic-gate } 2617c478bd9Sstevel@tonic-gate break; 2627c478bd9Sstevel@tonic-gate } 2637c478bd9Sstevel@tonic-gate ASSERT((dtyp == DT_CANCEL) || 2647c478bd9Sstevel@tonic-gate (!DATAoverlapME(mof, hnb, me)) || 2657c478bd9Sstevel@tonic-gate MEwithinDATA(me, mof, hnb)); 2667c478bd9Sstevel@tonic-gate } 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate if (me) { 2697c478bd9Sstevel@tonic-gate /* already in map */ 2707c478bd9Sstevel@tonic-gate continue; 2717c478bd9Sstevel@tonic-gate } 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate /* 2747c478bd9Sstevel@tonic-gate * Add up all the delta map deltas so we can compute 2757c478bd9Sstevel@tonic-gate * an upper bound on the log size used. 2767c478bd9Sstevel@tonic-gate * Note, some deltas get removed from the deltamap 2777c478bd9Sstevel@tonic-gate * before the deltamap_push by lufs_write_strategy 2787c478bd9Sstevel@tonic-gate * and so multiple deltas to the same mof offset 2797c478bd9Sstevel@tonic-gate * don't get cancelled here but in the logmap. 2807c478bd9Sstevel@tonic-gate * Thus we can't easily get a accurate count of 2817c478bd9Sstevel@tonic-gate * the log space used - only an upper bound. 2827c478bd9Sstevel@tonic-gate */ 2837c478bd9Sstevel@tonic-gate if (tp && (mtm->mtm_ul->un_deltamap == mtm)) { 2847c478bd9Sstevel@tonic-gate ASSERT(dtyp != DT_CANCEL); 2857c478bd9Sstevel@tonic-gate if (dtyp == DT_ABZERO) { 2867c478bd9Sstevel@tonic-gate tp->deltas_size += sizeof (struct delta); 2877c478bd9Sstevel@tonic-gate } else { 2887c478bd9Sstevel@tonic-gate tp->deltas_size += 2897c478bd9Sstevel@tonic-gate (hnb + sizeof (struct delta)); 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate } 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate delta_stats[dtyp]++; 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate /* 2967c478bd9Sstevel@tonic-gate * get a mapentry 2977c478bd9Sstevel@tonic-gate * May need to drop & re-grab the mtm_mutex 2987c478bd9Sstevel@tonic-gate * and then recheck for a duplicate 2997c478bd9Sstevel@tonic-gate */ 3007c478bd9Sstevel@tonic-gate me = kmem_cache_alloc(mapentry_cache, KM_NOSLEEP); 3017c478bd9Sstevel@tonic-gate if (me == NULL) { 3027c478bd9Sstevel@tonic-gate mutex_exit(&mtm->mtm_mutex); 3037c478bd9Sstevel@tonic-gate me = kmem_cache_alloc(mapentry_cache, KM_SLEEP); 3047c478bd9Sstevel@tonic-gate mutex_enter(&mtm->mtm_mutex); 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate bzero(me, sizeof (mapentry_t)); 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate /* 3097c478bd9Sstevel@tonic-gate * initialize and put in deltamap 3107c478bd9Sstevel@tonic-gate */ 3117c478bd9Sstevel@tonic-gate me->me_mof = mof; 3127c478bd9Sstevel@tonic-gate me->me_nb = hnb; 3137c478bd9Sstevel@tonic-gate me->me_func = func; 3147c478bd9Sstevel@tonic-gate me->me_arg = arg; 3157c478bd9Sstevel@tonic-gate me->me_dt = dtyp; 3167c478bd9Sstevel@tonic-gate me->me_flags = ME_HASH; 3177c478bd9Sstevel@tonic-gate me->me_tid = mtm->mtm_tid; 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate me->me_hash = *mep; 3207c478bd9Sstevel@tonic-gate *mep = me; 3217c478bd9Sstevel@tonic-gate me->me_next = (mapentry_t *)mtm; 3227c478bd9Sstevel@tonic-gate me->me_prev = mtm->mtm_prev; 3237c478bd9Sstevel@tonic-gate mtm->mtm_prev->me_next = me; 3247c478bd9Sstevel@tonic-gate mtm->mtm_prev = me; 3257c478bd9Sstevel@tonic-gate mtm->mtm_nme++; 3267c478bd9Sstevel@tonic-gate } 3277c478bd9Sstevel@tonic-gate mutex_exit(&mtm->mtm_mutex); 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate ASSERT(((mtm->mtm_debug & MT_CHECK_MAP) == 0) || 3307c478bd9Sstevel@tonic-gate map_check_linkage(mtm)); 3317c478bd9Sstevel@tonic-gate } 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate /* 3347c478bd9Sstevel@tonic-gate * remove deltas within (mof, nb) and return as linked list 3357c478bd9Sstevel@tonic-gate */ 3367c478bd9Sstevel@tonic-gate mapentry_t * 3377c478bd9Sstevel@tonic-gate deltamap_remove(mt_map_t *mtm, offset_t mof, off_t nb) 3387c478bd9Sstevel@tonic-gate { 3397c478bd9Sstevel@tonic-gate off_t hnb; 3407c478bd9Sstevel@tonic-gate mapentry_t *me; 3417c478bd9Sstevel@tonic-gate mapentry_t **mep; 3427c478bd9Sstevel@tonic-gate mapentry_t *mer; 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate if (mtm == NULL) 3457c478bd9Sstevel@tonic-gate return (NULL); 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate ASSERT(((mtm->mtm_debug & MT_CHECK_MAP) == 0) || 3487c478bd9Sstevel@tonic-gate map_check_linkage(mtm)); 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate mutex_enter(&mtm->mtm_mutex); 3517c478bd9Sstevel@tonic-gate for (mer = NULL, hnb = 0; nb; nb -= hnb, mof += hnb) { 3527c478bd9Sstevel@tonic-gate hnb = MAPBLOCKSIZE - (mof & MAPBLOCKOFF); 3537c478bd9Sstevel@tonic-gate if (hnb > nb) 3547c478bd9Sstevel@tonic-gate hnb = nb; 3557c478bd9Sstevel@tonic-gate /* 3567c478bd9Sstevel@tonic-gate * remove entries from hash and return as a aged linked list 3577c478bd9Sstevel@tonic-gate */ 3587c478bd9Sstevel@tonic-gate mep = MAP_HASH(mof, mtm); 3597c478bd9Sstevel@tonic-gate while ((me = *mep) != 0) { 3607c478bd9Sstevel@tonic-gate if (MEwithinDATA(me, mof, hnb)) { 3617c478bd9Sstevel@tonic-gate *mep = me->me_hash; 3627c478bd9Sstevel@tonic-gate me->me_next->me_prev = me->me_prev; 3637c478bd9Sstevel@tonic-gate me->me_prev->me_next = me->me_next; 3647c478bd9Sstevel@tonic-gate me->me_hash = mer; 3657c478bd9Sstevel@tonic-gate mer = me; 3667c478bd9Sstevel@tonic-gate me->me_flags |= ME_LIST; 3677c478bd9Sstevel@tonic-gate me->me_flags &= ~ME_HASH; 3687c478bd9Sstevel@tonic-gate mtm->mtm_nme--; 3697c478bd9Sstevel@tonic-gate } else 3707c478bd9Sstevel@tonic-gate mep = &me->me_hash; 3717c478bd9Sstevel@tonic-gate } 3727c478bd9Sstevel@tonic-gate } 3737c478bd9Sstevel@tonic-gate mutex_exit(&mtm->mtm_mutex); 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate ASSERT(((mtm->mtm_debug & MT_CHECK_MAP) == 0) || 3767c478bd9Sstevel@tonic-gate map_check_linkage(mtm)); 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate return (mer); 3797c478bd9Sstevel@tonic-gate } 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate /* 3827c478bd9Sstevel@tonic-gate * delete entries within (mof, nb) 3837c478bd9Sstevel@tonic-gate */ 3847c478bd9Sstevel@tonic-gate void 3857c478bd9Sstevel@tonic-gate deltamap_del(mt_map_t *mtm, offset_t mof, off_t nb) 3867c478bd9Sstevel@tonic-gate { 3877c478bd9Sstevel@tonic-gate mapentry_t *me; 3887c478bd9Sstevel@tonic-gate mapentry_t *menext; 3897c478bd9Sstevel@tonic-gate 3907c478bd9Sstevel@tonic-gate menext = deltamap_remove(mtm, mof, nb); 3917c478bd9Sstevel@tonic-gate while ((me = menext) != 0) { 3927c478bd9Sstevel@tonic-gate menext = me->me_hash; 3937c478bd9Sstevel@tonic-gate kmem_cache_free(mapentry_cache, me); 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate } 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate /* 3987c478bd9Sstevel@tonic-gate * Call the indicated function to cause deltas to move to the logmap. 3997c478bd9Sstevel@tonic-gate * top_end_sync() is the only caller of this function and 4007c478bd9Sstevel@tonic-gate * it has waited for the completion of all threads, so there can 4017c478bd9Sstevel@tonic-gate * be no other activity in the deltamap. Therefore we don't need to 4027c478bd9Sstevel@tonic-gate * hold the deltamap lock. 4037c478bd9Sstevel@tonic-gate */ 4047c478bd9Sstevel@tonic-gate void 4057c478bd9Sstevel@tonic-gate deltamap_push(ml_unit_t *ul) 4067c478bd9Sstevel@tonic-gate { 4077c478bd9Sstevel@tonic-gate delta_t dtyp; 4087c478bd9Sstevel@tonic-gate int (*func)(); 4097c478bd9Sstevel@tonic-gate ulong_t arg; 4107c478bd9Sstevel@tonic-gate mapentry_t *me; 4117c478bd9Sstevel@tonic-gate offset_t mof; 4127c478bd9Sstevel@tonic-gate off_t nb; 4137c478bd9Sstevel@tonic-gate mt_map_t *mtm = ul->un_deltamap; 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate ASSERT(((mtm->mtm_debug & MT_CHECK_MAP) == 0) || 4167c478bd9Sstevel@tonic-gate map_check_linkage(mtm)); 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate /* 4197c478bd9Sstevel@tonic-gate * for every entry in the deltamap 4207c478bd9Sstevel@tonic-gate */ 4217c478bd9Sstevel@tonic-gate while ((me = mtm->mtm_next) != (mapentry_t *)mtm) { 4227c478bd9Sstevel@tonic-gate ASSERT(me->me_func); 4237c478bd9Sstevel@tonic-gate func = me->me_func; 4247c478bd9Sstevel@tonic-gate dtyp = me->me_dt; 4257c478bd9Sstevel@tonic-gate arg = me->me_arg; 4267c478bd9Sstevel@tonic-gate mof = me->me_mof; 4277c478bd9Sstevel@tonic-gate nb = me->me_nb; 4287c478bd9Sstevel@tonic-gate if ((ul->un_flags & LDL_ERROR) || 4297c478bd9Sstevel@tonic-gate (*func)(ul->un_ufsvfs, dtyp, arg)) 4307c478bd9Sstevel@tonic-gate deltamap_del(mtm, mof, nb); 4317c478bd9Sstevel@tonic-gate } 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate ASSERT(((mtm->mtm_debug & MT_CHECK_MAP) == 0) || 4347c478bd9Sstevel@tonic-gate map_check_linkage(mtm)); 4357c478bd9Sstevel@tonic-gate } 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate /* 4387c478bd9Sstevel@tonic-gate * LOGMAP ROUTINES 4397c478bd9Sstevel@tonic-gate */ 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate int 4427c478bd9Sstevel@tonic-gate logmap_need_commit(mt_map_t *mtm) 4437c478bd9Sstevel@tonic-gate { 4447c478bd9Sstevel@tonic-gate return ((mtm->mtm_nmet > logmap_maxnme_commit) || 4457c478bd9Sstevel@tonic-gate (mtm->mtm_cfrags >= mtm->mtm_cfragmax)); 4467c478bd9Sstevel@tonic-gate } 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate int 4497c478bd9Sstevel@tonic-gate logmap_need_roll_async(mt_map_t *mtm) 4507c478bd9Sstevel@tonic-gate { 4517c478bd9Sstevel@tonic-gate return (mtm->mtm_nme > logmap_maxnme_async); 4527c478bd9Sstevel@tonic-gate } 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate int 4557c478bd9Sstevel@tonic-gate logmap_need_roll_sync(mt_map_t *mtm) 4567c478bd9Sstevel@tonic-gate { 4577c478bd9Sstevel@tonic-gate return (mtm->mtm_nme > logmap_maxnme_sync); 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate void 4617c478bd9Sstevel@tonic-gate logmap_start_roll(ml_unit_t *ul) 4627c478bd9Sstevel@tonic-gate { 4637c478bd9Sstevel@tonic-gate mt_map_t *logmap = ul->un_logmap; 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate logmap_settail(logmap, ul); 4667c478bd9Sstevel@tonic-gate ASSERT(!(ul->un_flags & LDL_NOROLL)); 4677c478bd9Sstevel@tonic-gate mutex_enter(&logmap->mtm_mutex); 4687c478bd9Sstevel@tonic-gate if ((logmap->mtm_flags & MTM_ROLL_RUNNING) == 0) { 4697c478bd9Sstevel@tonic-gate logmap->mtm_flags |= MTM_ROLL_RUNNING; 4707c478bd9Sstevel@tonic-gate logmap->mtm_flags &= ~(MTM_FORCE_ROLL | MTM_ROLL_EXIT); 4717c478bd9Sstevel@tonic-gate (void) thread_create(NULL, 0, trans_roll, ul, 0, &p0, 4727c478bd9Sstevel@tonic-gate TS_RUN, minclsyspri); 4737c478bd9Sstevel@tonic-gate } 4747c478bd9Sstevel@tonic-gate mutex_exit(&logmap->mtm_mutex); 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate void 4787c478bd9Sstevel@tonic-gate logmap_kill_roll(ml_unit_t *ul) 4797c478bd9Sstevel@tonic-gate { 4807c478bd9Sstevel@tonic-gate mt_map_t *mtm = ul->un_logmap; 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate if (mtm == NULL) 4837c478bd9Sstevel@tonic-gate return; 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate mutex_enter(&mtm->mtm_mutex); 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate while (mtm->mtm_flags & MTM_ROLL_RUNNING) { 4887c478bd9Sstevel@tonic-gate mtm->mtm_flags |= MTM_ROLL_EXIT; 4897c478bd9Sstevel@tonic-gate cv_signal(&mtm->mtm_to_roll_cv); 4907c478bd9Sstevel@tonic-gate cv_wait(&mtm->mtm_from_roll_cv, &mtm->mtm_mutex); 4917c478bd9Sstevel@tonic-gate } 4927c478bd9Sstevel@tonic-gate mutex_exit(&mtm->mtm_mutex); 4937c478bd9Sstevel@tonic-gate } 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate /* 4967c478bd9Sstevel@tonic-gate * kick the roll thread if it's not doing anything 4977c478bd9Sstevel@tonic-gate */ 4987c478bd9Sstevel@tonic-gate void 4997c478bd9Sstevel@tonic-gate logmap_forceroll_nowait(mt_map_t *logmap) 5007c478bd9Sstevel@tonic-gate { 5017c478bd9Sstevel@tonic-gate /* 5027c478bd9Sstevel@tonic-gate * Don't need to lock mtm_mutex to read mtm_flags here as we 5037c478bd9Sstevel@tonic-gate * don't care in the rare case when we get a transitional value 5047c478bd9Sstevel@tonic-gate * of mtm_flags. Just by signalling the thread it will wakeup 5057c478bd9Sstevel@tonic-gate * and notice it has too many logmap entries. 5067c478bd9Sstevel@tonic-gate */ 5077c478bd9Sstevel@tonic-gate ASSERT(!(logmap->mtm_ul->un_flags & LDL_NOROLL)); 5087c478bd9Sstevel@tonic-gate if ((logmap->mtm_flags & MTM_ROLLING) == 0) { 5097c478bd9Sstevel@tonic-gate cv_signal(&logmap->mtm_to_roll_cv); 5107c478bd9Sstevel@tonic-gate } 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate /* 5147c478bd9Sstevel@tonic-gate * kick the roll thread and wait for it to finish a cycle 5157c478bd9Sstevel@tonic-gate */ 5167c478bd9Sstevel@tonic-gate void 5177c478bd9Sstevel@tonic-gate logmap_forceroll(mt_map_t *mtm) 5187c478bd9Sstevel@tonic-gate { 5197c478bd9Sstevel@tonic-gate mutex_enter(&mtm->mtm_mutex); 5207c478bd9Sstevel@tonic-gate if ((mtm->mtm_flags & MTM_FORCE_ROLL) == 0) { 5217c478bd9Sstevel@tonic-gate mtm->mtm_flags |= MTM_FORCE_ROLL; 5227c478bd9Sstevel@tonic-gate cv_signal(&mtm->mtm_to_roll_cv); 5237c478bd9Sstevel@tonic-gate } 5247c478bd9Sstevel@tonic-gate do { 5257c478bd9Sstevel@tonic-gate if ((mtm->mtm_flags & MTM_ROLL_RUNNING) == 0) { 5267c478bd9Sstevel@tonic-gate mtm->mtm_flags &= ~MTM_FORCE_ROLL; 5277c478bd9Sstevel@tonic-gate goto out; 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate cv_wait(&mtm->mtm_from_roll_cv, &mtm->mtm_mutex); 5307c478bd9Sstevel@tonic-gate } while (mtm->mtm_flags & MTM_FORCE_ROLL); 5317c478bd9Sstevel@tonic-gate out: 5327c478bd9Sstevel@tonic-gate mutex_exit(&mtm->mtm_mutex); 5337c478bd9Sstevel@tonic-gate } 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate /* 5367c478bd9Sstevel@tonic-gate * remove rolled deltas within (mof, nb) and free them 5377c478bd9Sstevel@tonic-gate */ 5387c478bd9Sstevel@tonic-gate void 5397c478bd9Sstevel@tonic-gate logmap_remove_roll(mt_map_t *mtm, offset_t mof, off_t nb) 5407c478bd9Sstevel@tonic-gate { 5417c478bd9Sstevel@tonic-gate int dolock = 0; 5427c478bd9Sstevel@tonic-gate off_t hnb; 5437c478bd9Sstevel@tonic-gate mapentry_t *me; 5447c478bd9Sstevel@tonic-gate mapentry_t **mep; 5457c478bd9Sstevel@tonic-gate offset_t savmof = mof; 5467c478bd9Sstevel@tonic-gate off_t savnb = nb; 5477c478bd9Sstevel@tonic-gate 5487c478bd9Sstevel@tonic-gate ASSERT(((mtm->mtm_debug & MT_CHECK_MAP) == 0) || 5497c478bd9Sstevel@tonic-gate map_check_linkage(mtm)); 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate again: 5527c478bd9Sstevel@tonic-gate if (dolock) 5537c478bd9Sstevel@tonic-gate rw_enter(&mtm->mtm_rwlock, RW_WRITER); 5547c478bd9Sstevel@tonic-gate mutex_enter(&mtm->mtm_mutex); 5557c478bd9Sstevel@tonic-gate for (hnb = 0; nb; nb -= hnb, mof += hnb) { 5567c478bd9Sstevel@tonic-gate hnb = MAPBLOCKSIZE - (mof & MAPBLOCKOFF); 5577c478bd9Sstevel@tonic-gate if (hnb > nb) 5587c478bd9Sstevel@tonic-gate hnb = nb; 5597c478bd9Sstevel@tonic-gate /* 5607c478bd9Sstevel@tonic-gate * remove and free the rolled entries 5617c478bd9Sstevel@tonic-gate */ 5627c478bd9Sstevel@tonic-gate mep = MAP_HASH(mof, mtm); 5637c478bd9Sstevel@tonic-gate while ((me = *mep) != 0) { 5647c478bd9Sstevel@tonic-gate if ((me->me_flags & ME_ROLL) && 5657c478bd9Sstevel@tonic-gate (MEwithinDATA(me, mof, hnb))) { 5667c478bd9Sstevel@tonic-gate if (me->me_flags & ME_AGE) { 5677c478bd9Sstevel@tonic-gate ASSERT(dolock == 0); 5687c478bd9Sstevel@tonic-gate dolock = 1; 5697c478bd9Sstevel@tonic-gate mutex_exit(&mtm->mtm_mutex); 5707c478bd9Sstevel@tonic-gate mof = savmof; 5717c478bd9Sstevel@tonic-gate nb = savnb; 5727c478bd9Sstevel@tonic-gate goto again; 5737c478bd9Sstevel@tonic-gate } 5747c478bd9Sstevel@tonic-gate *mep = me->me_hash; 5757c478bd9Sstevel@tonic-gate me->me_next->me_prev = me->me_prev; 5767c478bd9Sstevel@tonic-gate me->me_prev->me_next = me->me_next; 5777c478bd9Sstevel@tonic-gate me->me_flags &= ~(ME_HASH|ME_ROLL); 5787c478bd9Sstevel@tonic-gate ASSERT(!(me->me_flags & ME_USER)); 5797c478bd9Sstevel@tonic-gate mtm->mtm_nme--; 5807c478bd9Sstevel@tonic-gate /* 5817c478bd9Sstevel@tonic-gate * cancelled entries are handled by someone else 5827c478bd9Sstevel@tonic-gate */ 5837c478bd9Sstevel@tonic-gate if ((me->me_flags & ME_CANCEL) == 0) { 5847c478bd9Sstevel@tonic-gate roll_stats[me->me_dt]++; 5857c478bd9Sstevel@tonic-gate CRB_RELE(me); 5867c478bd9Sstevel@tonic-gate kmem_cache_free(mapentry_cache, me); 5877c478bd9Sstevel@tonic-gate } 5887c478bd9Sstevel@tonic-gate } else 5897c478bd9Sstevel@tonic-gate mep = &me->me_hash; 5907c478bd9Sstevel@tonic-gate } 5917c478bd9Sstevel@tonic-gate } 5927c478bd9Sstevel@tonic-gate mutex_exit(&mtm->mtm_mutex); 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate ASSERT(((mtm->mtm_debug & MT_CHECK_MAP) == 0) || 5957c478bd9Sstevel@tonic-gate map_check_linkage(mtm)); 5967c478bd9Sstevel@tonic-gate 5977c478bd9Sstevel@tonic-gate if (dolock) 5987c478bd9Sstevel@tonic-gate rw_exit(&mtm->mtm_rwlock); 5997c478bd9Sstevel@tonic-gate } 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate /* 6027c478bd9Sstevel@tonic-gate * Find the disk offset of the next delta to roll. 6037c478bd9Sstevel@tonic-gate * Returns 0: no more deltas to roll or a transaction is being committed 6047c478bd9Sstevel@tonic-gate * 1: a delta to roll has been found and *mofp points 6057c478bd9Sstevel@tonic-gate * to the master file disk offset 6067c478bd9Sstevel@tonic-gate */ 6077c478bd9Sstevel@tonic-gate int 6087c478bd9Sstevel@tonic-gate logmap_next_roll(mt_map_t *logmap, offset_t *mofp) 6097c478bd9Sstevel@tonic-gate { 6107c478bd9Sstevel@tonic-gate mapentry_t *me; 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate ASSERT(((logmap->mtm_debug & MT_CHECK_MAP) == 0) || 6137c478bd9Sstevel@tonic-gate map_check_linkage(logmap)); 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate mutex_enter(&logmap->mtm_mutex); 6167c478bd9Sstevel@tonic-gate for (me = logmap->mtm_next; me != (mapentry_t *)logmap; 6177c478bd9Sstevel@tonic-gate me = me->me_next) { 6187c478bd9Sstevel@tonic-gate /* already rolled */ 6197c478bd9Sstevel@tonic-gate if (me->me_flags & ME_ROLL) { 6207c478bd9Sstevel@tonic-gate continue; 6217c478bd9Sstevel@tonic-gate } 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate /* part of currently busy transaction; stop */ 6247c478bd9Sstevel@tonic-gate if (me->me_tid == logmap->mtm_tid) { 6257c478bd9Sstevel@tonic-gate break; 6267c478bd9Sstevel@tonic-gate } 6277c478bd9Sstevel@tonic-gate 6287c478bd9Sstevel@tonic-gate /* part of commit-in-progress transaction; stop */ 6297c478bd9Sstevel@tonic-gate if (me->me_tid == logmap->mtm_committid) { 6307c478bd9Sstevel@tonic-gate break; 6317c478bd9Sstevel@tonic-gate } 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate /* 6347c478bd9Sstevel@tonic-gate * We shouldn't see a DT_CANCEL mapentry whose 6357c478bd9Sstevel@tonic-gate * tid != mtm_committid, or != mtm_tid since 6367c478bd9Sstevel@tonic-gate * these are removed at the end of each committed 6377c478bd9Sstevel@tonic-gate * transaction. 6387c478bd9Sstevel@tonic-gate */ 6397c478bd9Sstevel@tonic-gate ASSERT(!(me->me_dt == DT_CANCEL)); 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate *mofp = me->me_mof; 6427c478bd9Sstevel@tonic-gate mutex_exit(&logmap->mtm_mutex); 6437c478bd9Sstevel@tonic-gate return (1); 6447c478bd9Sstevel@tonic-gate } 6457c478bd9Sstevel@tonic-gate mutex_exit(&logmap->mtm_mutex); 6467c478bd9Sstevel@tonic-gate return (0); 6477c478bd9Sstevel@tonic-gate } 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate /* 6507c478bd9Sstevel@tonic-gate * put mapentry on sorted age list 6517c478bd9Sstevel@tonic-gate */ 6527c478bd9Sstevel@tonic-gate static void 6537c478bd9Sstevel@tonic-gate logmap_list_age(mapentry_t **age, mapentry_t *meadd) 6547c478bd9Sstevel@tonic-gate { 6557c478bd9Sstevel@tonic-gate mapentry_t *me; 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate ASSERT(!(meadd->me_flags & (ME_AGE|ME_LIST))); 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate for (me = *age; me; age = &me->me_agenext, me = *age) { 6607c478bd9Sstevel@tonic-gate if (me->me_age > meadd->me_age) 6617c478bd9Sstevel@tonic-gate break; 6627c478bd9Sstevel@tonic-gate } 6637c478bd9Sstevel@tonic-gate meadd->me_agenext = me; 6647c478bd9Sstevel@tonic-gate meadd->me_flags |= ME_AGE; 6657c478bd9Sstevel@tonic-gate *age = meadd; 6667c478bd9Sstevel@tonic-gate } 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate /* 6697c478bd9Sstevel@tonic-gate * get a list of deltas within <mof, mof+nb> 6707c478bd9Sstevel@tonic-gate * returns with mtm_rwlock held 6717c478bd9Sstevel@tonic-gate * return value says whether the entire mof range is covered by deltas 6727c478bd9Sstevel@tonic-gate */ 6737c478bd9Sstevel@tonic-gate int 6747c478bd9Sstevel@tonic-gate logmap_list_get( 6757c478bd9Sstevel@tonic-gate mt_map_t *mtm, 6767c478bd9Sstevel@tonic-gate offset_t mof, 6777c478bd9Sstevel@tonic-gate off_t nb, 6787c478bd9Sstevel@tonic-gate mapentry_t **age) 6797c478bd9Sstevel@tonic-gate { 6807c478bd9Sstevel@tonic-gate off_t hnb; 6817c478bd9Sstevel@tonic-gate mapentry_t *me; 6827c478bd9Sstevel@tonic-gate mapentry_t **mep; 6837c478bd9Sstevel@tonic-gate int rwtype = RW_READER; 6847c478bd9Sstevel@tonic-gate offset_t savmof = mof; 6857c478bd9Sstevel@tonic-gate off_t savnb = nb; 6867c478bd9Sstevel@tonic-gate int entire = 0; 6877c478bd9Sstevel@tonic-gate crb_t *crb; 6887c478bd9Sstevel@tonic-gate 6897c478bd9Sstevel@tonic-gate mtm->mtm_ref = 1; 6907c478bd9Sstevel@tonic-gate again: 6917c478bd9Sstevel@tonic-gate 6927c478bd9Sstevel@tonic-gate ASSERT(((mtm->mtm_debug & MT_CHECK_MAP) == 0) || 6937c478bd9Sstevel@tonic-gate map_check_linkage(mtm)); 6947c478bd9Sstevel@tonic-gate 6957c478bd9Sstevel@tonic-gate rw_enter(&mtm->mtm_rwlock, rwtype); 6967c478bd9Sstevel@tonic-gate *age = NULL; 6977c478bd9Sstevel@tonic-gate mutex_enter(&mtm->mtm_mutex); 6987c478bd9Sstevel@tonic-gate for (hnb = 0; nb; nb -= hnb, mof += hnb) { 6997c478bd9Sstevel@tonic-gate hnb = MAPBLOCKSIZE - (mof & MAPBLOCKOFF); 7007c478bd9Sstevel@tonic-gate if (hnb > nb) 7017c478bd9Sstevel@tonic-gate hnb = nb; 7027c478bd9Sstevel@tonic-gate /* 7037c478bd9Sstevel@tonic-gate * find overlapping entries 7047c478bd9Sstevel@tonic-gate */ 7057c478bd9Sstevel@tonic-gate mep = MAP_HASH(mof, mtm); 7067c478bd9Sstevel@tonic-gate for (me = *mep; me; me = me->me_hash) { 7077c478bd9Sstevel@tonic-gate if (me->me_dt == DT_CANCEL) 7087c478bd9Sstevel@tonic-gate continue; 7097c478bd9Sstevel@tonic-gate if (!DATAoverlapME(mof, hnb, me)) 7107c478bd9Sstevel@tonic-gate continue; 7117c478bd9Sstevel@tonic-gate /* 7127c478bd9Sstevel@tonic-gate * check if map entry is in use 7137c478bd9Sstevel@tonic-gate * (about to be rolled). 7147c478bd9Sstevel@tonic-gate */ 7157c478bd9Sstevel@tonic-gate if (me->me_flags & ME_AGE) { 7167c478bd9Sstevel@tonic-gate /* 7177c478bd9Sstevel@tonic-gate * reset the age bit in the list, 7187c478bd9Sstevel@tonic-gate * upgrade the lock, and try again 7197c478bd9Sstevel@tonic-gate */ 7207c478bd9Sstevel@tonic-gate for (me = *age; me; me = *age) { 7217c478bd9Sstevel@tonic-gate *age = me->me_agenext; 7227c478bd9Sstevel@tonic-gate me->me_flags &= ~ME_AGE; 7237c478bd9Sstevel@tonic-gate } 7247c478bd9Sstevel@tonic-gate mutex_exit(&mtm->mtm_mutex); 7257c478bd9Sstevel@tonic-gate rw_exit(&mtm->mtm_rwlock); 7267c478bd9Sstevel@tonic-gate rwtype = RW_WRITER; 7277c478bd9Sstevel@tonic-gate mof = savmof; 7287c478bd9Sstevel@tonic-gate nb = savnb; 7297c478bd9Sstevel@tonic-gate entire = 0; 7307c478bd9Sstevel@tonic-gate goto again; 7317c478bd9Sstevel@tonic-gate } else { 7327c478bd9Sstevel@tonic-gate /* add mapentry to age ordered list */ 7337c478bd9Sstevel@tonic-gate logmap_list_age(age, me); 7347c478bd9Sstevel@tonic-gate crb = me->me_crb; 7357c478bd9Sstevel@tonic-gate if (crb) { 7367c478bd9Sstevel@tonic-gate if (DATAwithinCRB(savmof, savnb, crb)) { 7377c478bd9Sstevel@tonic-gate entire = 1; 7387c478bd9Sstevel@tonic-gate } 7397c478bd9Sstevel@tonic-gate } else { 7407c478bd9Sstevel@tonic-gate if (DATAwithinME(savmof, savnb, me)) { 7417c478bd9Sstevel@tonic-gate entire = 1; 7427c478bd9Sstevel@tonic-gate } 7437c478bd9Sstevel@tonic-gate } 7447c478bd9Sstevel@tonic-gate } 7457c478bd9Sstevel@tonic-gate } 7467c478bd9Sstevel@tonic-gate } 7477c478bd9Sstevel@tonic-gate mutex_exit(&mtm->mtm_mutex); 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate ASSERT(RW_LOCK_HELD(&mtm->mtm_rwlock)); 7507c478bd9Sstevel@tonic-gate return (entire); 7517c478bd9Sstevel@tonic-gate } 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate /* 7547c478bd9Sstevel@tonic-gate * Get a list of deltas for rolling - returns sucess or failure. 7557c478bd9Sstevel@tonic-gate * Also return the cached roll buffer if all deltas point to it. 7567c478bd9Sstevel@tonic-gate */ 7577c478bd9Sstevel@tonic-gate int 7587c478bd9Sstevel@tonic-gate logmap_list_get_roll(mt_map_t *logmap, offset_t mof, rollbuf_t *rbp) 7597c478bd9Sstevel@tonic-gate { 7607c478bd9Sstevel@tonic-gate mapentry_t *me, **mep, *age = NULL; 7617c478bd9Sstevel@tonic-gate crb_t *crb = NULL; 7627c478bd9Sstevel@tonic-gate 7637c478bd9Sstevel@tonic-gate ASSERT(RW_LOCK_HELD(&logmap->mtm_rwlock)); 7647c478bd9Sstevel@tonic-gate ASSERT(((logmap->mtm_debug & MT_CHECK_MAP) == 0) || 7657c478bd9Sstevel@tonic-gate map_check_linkage(logmap)); 7667c478bd9Sstevel@tonic-gate ASSERT((mof & MAPBLOCKOFF) == 0); 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate rbp->rb_crb = NULL; 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate /* 7717c478bd9Sstevel@tonic-gate * find overlapping entries 7727c478bd9Sstevel@tonic-gate */ 7737c478bd9Sstevel@tonic-gate mutex_enter(&logmap->mtm_mutex); 7747c478bd9Sstevel@tonic-gate mep = MAP_HASH(mof, logmap); 7757c478bd9Sstevel@tonic-gate for (me = *mep; me; me = me->me_hash) { 7767c478bd9Sstevel@tonic-gate if (!DATAoverlapME(mof, MAPBLOCKSIZE, me)) 7777c478bd9Sstevel@tonic-gate continue; 7787c478bd9Sstevel@tonic-gate if (me->me_tid == logmap->mtm_tid) 7797c478bd9Sstevel@tonic-gate continue; 7807c478bd9Sstevel@tonic-gate if (me->me_tid == logmap->mtm_committid) 7817c478bd9Sstevel@tonic-gate continue; 7827c478bd9Sstevel@tonic-gate if (me->me_dt == DT_CANCEL) 7837c478bd9Sstevel@tonic-gate continue; 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate /* 7867c478bd9Sstevel@tonic-gate * Check if map entry is in use (by lufs_read_strategy()) 7877c478bd9Sstevel@tonic-gate * and if so reset the age bit in the list, 7887c478bd9Sstevel@tonic-gate * upgrade the lock, and try again 7897c478bd9Sstevel@tonic-gate */ 7907c478bd9Sstevel@tonic-gate if (me->me_flags & ME_AGE) { 7917c478bd9Sstevel@tonic-gate for (me = age; me; me = age) { 7927c478bd9Sstevel@tonic-gate age = me->me_agenext; 7937c478bd9Sstevel@tonic-gate me->me_flags &= ~ME_AGE; 7947c478bd9Sstevel@tonic-gate } 7957c478bd9Sstevel@tonic-gate mutex_exit(&logmap->mtm_mutex); 7967c478bd9Sstevel@tonic-gate return (1); /* failure */ 7977c478bd9Sstevel@tonic-gate } else { 7987c478bd9Sstevel@tonic-gate /* add mapentry to age ordered list */ 7997c478bd9Sstevel@tonic-gate logmap_list_age(&age, me); 8007c478bd9Sstevel@tonic-gate } 8017c478bd9Sstevel@tonic-gate } 8027c478bd9Sstevel@tonic-gate if (!age) { 8037c478bd9Sstevel@tonic-gate goto out; 8047c478bd9Sstevel@tonic-gate } 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate /* 8077c478bd9Sstevel@tonic-gate * Mark the deltas as being rolled. 8087c478bd9Sstevel@tonic-gate */ 8097c478bd9Sstevel@tonic-gate for (me = age; me; me = me->me_agenext) { 8107c478bd9Sstevel@tonic-gate me->me_flags |= ME_ROLL; 8117c478bd9Sstevel@tonic-gate } 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate /* 8147c478bd9Sstevel@tonic-gate * Test if all deltas are covered by one valid roll buffer 8157c478bd9Sstevel@tonic-gate */ 8167c478bd9Sstevel@tonic-gate crb = age->me_crb; 8177c478bd9Sstevel@tonic-gate if (crb && !(crb->c_invalid)) { 8187c478bd9Sstevel@tonic-gate for (me = age; me; me = me->me_agenext) { 8197c478bd9Sstevel@tonic-gate if (me->me_crb != crb) { 8207c478bd9Sstevel@tonic-gate crb = NULL; 8217c478bd9Sstevel@tonic-gate break; 8227c478bd9Sstevel@tonic-gate } 8237c478bd9Sstevel@tonic-gate } 8247c478bd9Sstevel@tonic-gate rbp->rb_crb = crb; 8257c478bd9Sstevel@tonic-gate } 8267c478bd9Sstevel@tonic-gate out: 8277c478bd9Sstevel@tonic-gate rbp->rb_age = age; 8287c478bd9Sstevel@tonic-gate 8297c478bd9Sstevel@tonic-gate mutex_exit(&logmap->mtm_mutex); 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate ASSERT(((logmap->mtm_debug & MT_SCAN) == 0) || 8327c478bd9Sstevel@tonic-gate logmap_logscan_debug(logmap, age)); 8337c478bd9Sstevel@tonic-gate ASSERT(RW_LOCK_HELD(&logmap->mtm_rwlock)); 8347c478bd9Sstevel@tonic-gate return (0); /* success */ 8357c478bd9Sstevel@tonic-gate } 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate void 8387c478bd9Sstevel@tonic-gate logmap_list_put_roll(mt_map_t *mtm, mapentry_t *age) 8397c478bd9Sstevel@tonic-gate { 8407c478bd9Sstevel@tonic-gate mapentry_t *me; 8417c478bd9Sstevel@tonic-gate 8427c478bd9Sstevel@tonic-gate ASSERT(RW_LOCK_HELD(&mtm->mtm_rwlock)); 8437c478bd9Sstevel@tonic-gate mutex_enter(&mtm->mtm_mutex); 8447c478bd9Sstevel@tonic-gate for (me = age; me; me = age) { 8457c478bd9Sstevel@tonic-gate age = me->me_agenext; 8467c478bd9Sstevel@tonic-gate me->me_flags &= ~ME_AGE; 8477c478bd9Sstevel@tonic-gate } 8487c478bd9Sstevel@tonic-gate mutex_exit(&mtm->mtm_mutex); 8497c478bd9Sstevel@tonic-gate } 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate void 8527c478bd9Sstevel@tonic-gate logmap_list_put(mt_map_t *mtm, mapentry_t *age) 8537c478bd9Sstevel@tonic-gate { 8547c478bd9Sstevel@tonic-gate mapentry_t *me; 8557c478bd9Sstevel@tonic-gate 8567c478bd9Sstevel@tonic-gate ASSERT(RW_LOCK_HELD(&mtm->mtm_rwlock)); 8577c478bd9Sstevel@tonic-gate mutex_enter(&mtm->mtm_mutex); 8587c478bd9Sstevel@tonic-gate for (me = age; me; me = age) { 8597c478bd9Sstevel@tonic-gate age = me->me_agenext; 8607c478bd9Sstevel@tonic-gate me->me_flags &= ~ME_AGE; 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate mutex_exit(&mtm->mtm_mutex); 8637c478bd9Sstevel@tonic-gate rw_exit(&mtm->mtm_rwlock); 8647c478bd9Sstevel@tonic-gate } 8657c478bd9Sstevel@tonic-gate 8667c478bd9Sstevel@tonic-gate #define UFS_RW_BALANCE 2 8677c478bd9Sstevel@tonic-gate int ufs_rw_balance = UFS_RW_BALANCE; 8687c478bd9Sstevel@tonic-gate 8697c478bd9Sstevel@tonic-gate /* 8707c478bd9Sstevel@tonic-gate * Check if we need to read the master. 8717c478bd9Sstevel@tonic-gate * The master does not need to be read if the log deltas to the 8727c478bd9Sstevel@tonic-gate * block are for one contiguous set of full disk sectors. 8737c478bd9Sstevel@tonic-gate * Both cylinder group bit maps DT_CG (8K); directory entries (512B); 8747c478bd9Sstevel@tonic-gate * and possibly others should not require master disk reads. 8757c478bd9Sstevel@tonic-gate * Calculate the sector map for writing later. 8767c478bd9Sstevel@tonic-gate */ 8777c478bd9Sstevel@tonic-gate int 8787c478bd9Sstevel@tonic-gate logmap_setup_read(mapentry_t *age, rollbuf_t *rbp) 8797c478bd9Sstevel@tonic-gate { 8807c478bd9Sstevel@tonic-gate offset_t mof; 8817c478bd9Sstevel@tonic-gate crb_t *crb; 8827c478bd9Sstevel@tonic-gate mapentry_t *me; 8837c478bd9Sstevel@tonic-gate int32_t nb; 8847c478bd9Sstevel@tonic-gate int i; 8857c478bd9Sstevel@tonic-gate int start_sec, end_sec; 8867c478bd9Sstevel@tonic-gate int read_needed = 0; 8877c478bd9Sstevel@tonic-gate int all_inodes = 1; 8887c478bd9Sstevel@tonic-gate int first_sec = INT_MAX; 8897c478bd9Sstevel@tonic-gate int last_sec = -1; 8907c478bd9Sstevel@tonic-gate rbsecmap_t secmap = 0; 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate /* LINTED: warning: logical expression always true: op "||" */ 8937c478bd9Sstevel@tonic-gate ASSERT((MAPBLOCKSIZE / DEV_BSIZE) == (sizeof (secmap) * NBBY)); 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate for (me = age; me; me = me->me_agenext) { 8967c478bd9Sstevel@tonic-gate crb = me->me_crb; 8977c478bd9Sstevel@tonic-gate if (crb) { 8987c478bd9Sstevel@tonic-gate nb = crb->c_nb; 8997c478bd9Sstevel@tonic-gate mof = crb->c_mof; 9007c478bd9Sstevel@tonic-gate } else { 9017c478bd9Sstevel@tonic-gate nb = me->me_nb; 9027c478bd9Sstevel@tonic-gate mof = me->me_mof; 9037c478bd9Sstevel@tonic-gate } 9047c478bd9Sstevel@tonic-gate 9057c478bd9Sstevel@tonic-gate /* 9067c478bd9Sstevel@tonic-gate * If the delta is not sector aligned then 9077c478bd9Sstevel@tonic-gate * read the whole block. 9087c478bd9Sstevel@tonic-gate */ 9097c478bd9Sstevel@tonic-gate if ((nb & DEV_BMASK) || (mof & DEV_BMASK)) { 9107c478bd9Sstevel@tonic-gate read_needed = 1; 9117c478bd9Sstevel@tonic-gate } 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate /* Set sector map used in the MAPBLOCKSIZE block. */ 9147c478bd9Sstevel@tonic-gate start_sec = (mof & MAPBLOCKOFF) >> DEV_BSHIFT; 9157c478bd9Sstevel@tonic-gate end_sec = start_sec + ((nb - 1) >> DEV_BSHIFT); 9167c478bd9Sstevel@tonic-gate for (i = start_sec; i <= end_sec; i++) { 9177c478bd9Sstevel@tonic-gate secmap |= UINT16_C(1) << i; 9187c478bd9Sstevel@tonic-gate } 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate if (me->me_dt != DT_INODE) { 9217c478bd9Sstevel@tonic-gate all_inodes = 0; 9227c478bd9Sstevel@tonic-gate } 9237c478bd9Sstevel@tonic-gate if (start_sec < first_sec) { 9247c478bd9Sstevel@tonic-gate first_sec = start_sec; 9257c478bd9Sstevel@tonic-gate } 9267c478bd9Sstevel@tonic-gate if (end_sec > last_sec) { 9277c478bd9Sstevel@tonic-gate last_sec = end_sec; 9287c478bd9Sstevel@tonic-gate } 9297c478bd9Sstevel@tonic-gate } 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate ASSERT(secmap); 9327c478bd9Sstevel@tonic-gate ASSERT(first_sec != INT_MAX); 9337c478bd9Sstevel@tonic-gate ASSERT(last_sec != -1); 9347c478bd9Sstevel@tonic-gate 9357c478bd9Sstevel@tonic-gate if (all_inodes) { 9367c478bd9Sstevel@tonic-gate /* 9377c478bd9Sstevel@tonic-gate * Here we have a tradeoff choice. It must be better to 9387c478bd9Sstevel@tonic-gate * do 2 writes * in the same MAPBLOCKSIZE chunk, than a 9397c478bd9Sstevel@tonic-gate * read and a write. But what about 3 or more writes, versus 9407c478bd9Sstevel@tonic-gate * a read+write? * Where is the cut over? It will depend on 9417c478bd9Sstevel@tonic-gate * the track caching, scsi driver and other activity. 9427c478bd9Sstevel@tonic-gate * A unpublished tunable is defined (ufs_rw_balance) that 9437c478bd9Sstevel@tonic-gate * currently defaults to 2. 9447c478bd9Sstevel@tonic-gate */ 9457c478bd9Sstevel@tonic-gate if (!read_needed) { 9467c478bd9Sstevel@tonic-gate int count = 0, gap = 0; 9477c478bd9Sstevel@tonic-gate int sector_set; /* write needed to this sector */ 9487c478bd9Sstevel@tonic-gate 9497c478bd9Sstevel@tonic-gate /* Count the gaps (every 1 to 0 transation) */ 9507c478bd9Sstevel@tonic-gate for (i = first_sec + 1; i < last_sec; i++) { 9517c478bd9Sstevel@tonic-gate sector_set = secmap & (UINT16_C(1) << i); 9527c478bd9Sstevel@tonic-gate if (!gap && !sector_set) { 9537c478bd9Sstevel@tonic-gate gap = 1; 9547c478bd9Sstevel@tonic-gate count++; 9557c478bd9Sstevel@tonic-gate if (count > ufs_rw_balance) { 9567c478bd9Sstevel@tonic-gate read_needed = 1; 9577c478bd9Sstevel@tonic-gate break; 9587c478bd9Sstevel@tonic-gate } 9597c478bd9Sstevel@tonic-gate } else if (gap && sector_set) { 9607c478bd9Sstevel@tonic-gate gap = 0; 9617c478bd9Sstevel@tonic-gate } 9627c478bd9Sstevel@tonic-gate } 9637c478bd9Sstevel@tonic-gate } 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate /* 9667c478bd9Sstevel@tonic-gate * Inodes commonly make up the majority (~85%) of deltas. 9677c478bd9Sstevel@tonic-gate * They cannot contain embedded user data, so its safe to 9687c478bd9Sstevel@tonic-gate * read and write them all in one IO. 9697c478bd9Sstevel@tonic-gate * But for directory entries, shadow inode data, and 9707c478bd9Sstevel@tonic-gate * quota record data the user data fragments can be embedded 9717c478bd9Sstevel@tonic-gate * betwen those metadata, and so its not safe to read, modify 9727c478bd9Sstevel@tonic-gate * then write the entire range as user asynchronous user data 9737c478bd9Sstevel@tonic-gate * writes could get overwritten with old data. 9747c478bd9Sstevel@tonic-gate * Thus we have to create a segment map of meta data that 9757c478bd9Sstevel@tonic-gate * needs to get written. 9767c478bd9Sstevel@tonic-gate * 9777c478bd9Sstevel@tonic-gate * If user data was logged then this issue would go away. 9787c478bd9Sstevel@tonic-gate */ 9797c478bd9Sstevel@tonic-gate if (read_needed) { 9807c478bd9Sstevel@tonic-gate for (i = first_sec + 1; i < last_sec; i++) { 9817c478bd9Sstevel@tonic-gate secmap |= (UINT16_C(1) << i); 9827c478bd9Sstevel@tonic-gate } 9837c478bd9Sstevel@tonic-gate } 9847c478bd9Sstevel@tonic-gate } 9857c478bd9Sstevel@tonic-gate rbp->rb_secmap = secmap; 9867c478bd9Sstevel@tonic-gate return (read_needed); 9877c478bd9Sstevel@tonic-gate } 9887c478bd9Sstevel@tonic-gate 9897c478bd9Sstevel@tonic-gate /* 9907c478bd9Sstevel@tonic-gate * Abort the load of a set of log map delta's. 9917c478bd9Sstevel@tonic-gate * ie, 9927c478bd9Sstevel@tonic-gate * Clear out all mapentries on this unit's log map 9937c478bd9Sstevel@tonic-gate * which have a tid (transaction id) equal to the 9947c478bd9Sstevel@tonic-gate * parameter tid. Walk the cancel list, taking everything 9957c478bd9Sstevel@tonic-gate * off it, too. 9967c478bd9Sstevel@tonic-gate */ 9977c478bd9Sstevel@tonic-gate static void 9987c478bd9Sstevel@tonic-gate logmap_abort(ml_unit_t *ul, uint32_t tid) 9997c478bd9Sstevel@tonic-gate { 10007c478bd9Sstevel@tonic-gate struct mt_map *mtm = ul->un_logmap; /* Log map */ 100180d34432Sfrankho mapentry_t *me, **mep; 10027c478bd9Sstevel@tonic-gate int i; 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate ASSERT(((mtm->mtm_debug & MT_CHECK_MAP) == 0) || 10057c478bd9Sstevel@tonic-gate map_check_linkage(mtm)); 10067c478bd9Sstevel@tonic-gate 10077c478bd9Sstevel@tonic-gate /* 10087c478bd9Sstevel@tonic-gate * wait for any outstanding reads to finish; lock out future reads 10097c478bd9Sstevel@tonic-gate */ 10107c478bd9Sstevel@tonic-gate rw_enter(&mtm->mtm_rwlock, RW_WRITER); 10117c478bd9Sstevel@tonic-gate 10127c478bd9Sstevel@tonic-gate mutex_enter(&mtm->mtm_mutex); 10137c478bd9Sstevel@tonic-gate /* Take everything off cancel list */ 10147c478bd9Sstevel@tonic-gate while ((me = mtm->mtm_cancel) != NULL) { 10157c478bd9Sstevel@tonic-gate mtm->mtm_cancel = me->me_cancel; 10167c478bd9Sstevel@tonic-gate me->me_flags &= ~ME_CANCEL; 10177c478bd9Sstevel@tonic-gate me->me_cancel = NULL; 10187c478bd9Sstevel@tonic-gate } 10197c478bd9Sstevel@tonic-gate 10207c478bd9Sstevel@tonic-gate /* 10217c478bd9Sstevel@tonic-gate * Now take out all mapentries with current tid, and committid 10227c478bd9Sstevel@tonic-gate * as this function is called from logmap_logscan and logmap_commit 10237c478bd9Sstevel@tonic-gate * When it is called from logmap_logscan mtm_tid == mtm_committid 10247c478bd9Sstevel@tonic-gate * But when logmap_abort is called from logmap_commit it is 10257c478bd9Sstevel@tonic-gate * because the log errored when trying to write the commit record, 10267c478bd9Sstevel@tonic-gate * after the async ops have been allowed to start in top_end_sync. 10277c478bd9Sstevel@tonic-gate * So we also need to remove all mapentries from the transaction whose 10287c478bd9Sstevel@tonic-gate * commit failed. 10297c478bd9Sstevel@tonic-gate */ 10307c478bd9Sstevel@tonic-gate for (i = 0; i < mtm->mtm_nhash; i++) { 10317c478bd9Sstevel@tonic-gate mep = &mtm->mtm_hash[i]; 10327c478bd9Sstevel@tonic-gate while ((me = *mep) != NULL) { 10337c478bd9Sstevel@tonic-gate if (me->me_tid == tid || 10347c478bd9Sstevel@tonic-gate me->me_tid == mtm->mtm_committid) { 10357c478bd9Sstevel@tonic-gate *mep = me->me_hash; 10367c478bd9Sstevel@tonic-gate me->me_next->me_prev = me->me_prev; 10377c478bd9Sstevel@tonic-gate me->me_prev->me_next = me->me_next; 10387c478bd9Sstevel@tonic-gate if (!(me->me_flags & ME_USER)) { 10397c478bd9Sstevel@tonic-gate mtm->mtm_nme--; 10407c478bd9Sstevel@tonic-gate } 10417c478bd9Sstevel@tonic-gate CRB_RELE(me); 10427c478bd9Sstevel@tonic-gate kmem_cache_free(mapentry_cache, me); 10437c478bd9Sstevel@tonic-gate continue; 10447c478bd9Sstevel@tonic-gate } 10457c478bd9Sstevel@tonic-gate mep = &me->me_hash; 10467c478bd9Sstevel@tonic-gate } 10477c478bd9Sstevel@tonic-gate } 10487c478bd9Sstevel@tonic-gate 10497c478bd9Sstevel@tonic-gate if (!(ul->un_flags & LDL_SCAN)) 10507c478bd9Sstevel@tonic-gate mtm->mtm_flags |= MTM_CANCELED; 10517c478bd9Sstevel@tonic-gate mutex_exit(&mtm->mtm_mutex); 10527c478bd9Sstevel@tonic-gate mtm->mtm_dirty = 0; 10537c478bd9Sstevel@tonic-gate mtm->mtm_nmet = 0; 10547c478bd9Sstevel@tonic-gate rw_exit(&mtm->mtm_rwlock); 10557c478bd9Sstevel@tonic-gate 10567c478bd9Sstevel@tonic-gate ASSERT(((mtm->mtm_debug & MT_CHECK_MAP) == 0) || 10577c478bd9Sstevel@tonic-gate map_check_linkage(mtm)); 10587c478bd9Sstevel@tonic-gate } 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate static void 10617c478bd9Sstevel@tonic-gate logmap_wait_space(mt_map_t *mtm, ml_unit_t *ul, mapentry_t *me) 10627c478bd9Sstevel@tonic-gate { 10637c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ul->un_log_mutex)); 10647c478bd9Sstevel@tonic-gate 10657c478bd9Sstevel@tonic-gate while (!ldl_has_space(ul, me)) { 10667c478bd9Sstevel@tonic-gate ASSERT(!(ul->un_flags & LDL_NOROLL)); 10677c478bd9Sstevel@tonic-gate mutex_exit(&ul->un_log_mutex); 10687c478bd9Sstevel@tonic-gate logmap_forceroll(mtm); 10697c478bd9Sstevel@tonic-gate mutex_enter(&ul->un_log_mutex); 10707c478bd9Sstevel@tonic-gate if (ul->un_flags & LDL_ERROR) 10717c478bd9Sstevel@tonic-gate break; 10727c478bd9Sstevel@tonic-gate } 10737c478bd9Sstevel@tonic-gate 10747c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ul->un_log_mutex)); 10757c478bd9Sstevel@tonic-gate } 10767c478bd9Sstevel@tonic-gate 10777c478bd9Sstevel@tonic-gate /* 10787c478bd9Sstevel@tonic-gate * put a list of deltas into a logmap 10797c478bd9Sstevel@tonic-gate * If va == NULL, don't write to the log. 10807c478bd9Sstevel@tonic-gate */ 10817c478bd9Sstevel@tonic-gate void 10827c478bd9Sstevel@tonic-gate logmap_add( 10837c478bd9Sstevel@tonic-gate ml_unit_t *ul, 10847c478bd9Sstevel@tonic-gate char *va, /* Ptr to buf w/deltas & data */ 10857c478bd9Sstevel@tonic-gate offset_t vamof, /* Offset on master of buf start */ 10867c478bd9Sstevel@tonic-gate mapentry_t *melist) /* Entries to add */ 10877c478bd9Sstevel@tonic-gate { 10887c478bd9Sstevel@tonic-gate offset_t mof; 10897c478bd9Sstevel@tonic-gate off_t nb; 10907c478bd9Sstevel@tonic-gate mapentry_t *me; 10917c478bd9Sstevel@tonic-gate mapentry_t **mep; 10927c478bd9Sstevel@tonic-gate mapentry_t **savmep; 10937c478bd9Sstevel@tonic-gate uint32_t tid; 10947c478bd9Sstevel@tonic-gate mt_map_t *mtm = ul->un_logmap; 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate mutex_enter(&ul->un_log_mutex); 10977c478bd9Sstevel@tonic-gate if (va) 10987c478bd9Sstevel@tonic-gate logmap_wait_space(mtm, ul, melist); 10997c478bd9Sstevel@tonic-gate 11007c478bd9Sstevel@tonic-gate ASSERT(((mtm->mtm_debug & MT_CHECK_MAP) == 0) || 11017c478bd9Sstevel@tonic-gate map_check_linkage(mtm)); 11027c478bd9Sstevel@tonic-gate 11037c478bd9Sstevel@tonic-gate mtm->mtm_ref = 1; 11047c478bd9Sstevel@tonic-gate mtm->mtm_dirty++; 11057c478bd9Sstevel@tonic-gate tid = mtm->mtm_tid; 11067c478bd9Sstevel@tonic-gate while (melist) { 11077c478bd9Sstevel@tonic-gate mof = melist->me_mof; 11087c478bd9Sstevel@tonic-gate nb = melist->me_nb; 11097c478bd9Sstevel@tonic-gate 11107c478bd9Sstevel@tonic-gate /* 11117c478bd9Sstevel@tonic-gate * search for overlaping entries 11127c478bd9Sstevel@tonic-gate */ 11137c478bd9Sstevel@tonic-gate savmep = mep = MAP_HASH(mof, mtm); 11147c478bd9Sstevel@tonic-gate mutex_enter(&mtm->mtm_mutex); 11157c478bd9Sstevel@tonic-gate while ((me = *mep) != 0) { 11167c478bd9Sstevel@tonic-gate /* 11177c478bd9Sstevel@tonic-gate * Data consumes old map entry; cancel map entry. 11187c478bd9Sstevel@tonic-gate * Take care when we replace an old map entry 11197c478bd9Sstevel@tonic-gate * which carries quota information with a newer entry 11207c478bd9Sstevel@tonic-gate * which does not. In that case the push function 11217c478bd9Sstevel@tonic-gate * would not be called to clean up the dquot structure. 11227c478bd9Sstevel@tonic-gate * This would be found later by invalidatedq() causing 11237c478bd9Sstevel@tonic-gate * a panic when the filesystem in unmounted. 11247c478bd9Sstevel@tonic-gate * We clean up the dquot manually and then replace 11257c478bd9Sstevel@tonic-gate * the map entry. 11267c478bd9Sstevel@tonic-gate */ 11277c478bd9Sstevel@tonic-gate if (MEwithinDATA(me, mof, nb) && 11287c478bd9Sstevel@tonic-gate ((me->me_flags & (ME_ROLL|ME_CANCEL)) == 0)) { 11297c478bd9Sstevel@tonic-gate if (tid == me->me_tid && 11307c478bd9Sstevel@tonic-gate ((me->me_flags & ME_AGE) == 0)) { 11317c478bd9Sstevel@tonic-gate *mep = me->me_hash; 11327c478bd9Sstevel@tonic-gate me->me_next->me_prev = me->me_prev; 11337c478bd9Sstevel@tonic-gate me->me_prev->me_next = me->me_next; 11347c478bd9Sstevel@tonic-gate ASSERT(!(me->me_flags & ME_USER)); 11357c478bd9Sstevel@tonic-gate mtm->mtm_nme--; 11367c478bd9Sstevel@tonic-gate /* 11377c478bd9Sstevel@tonic-gate * Special case if the mapentry 11387c478bd9Sstevel@tonic-gate * carries a dquot and a push function. 11397c478bd9Sstevel@tonic-gate * We have to clean up the quota info 11407c478bd9Sstevel@tonic-gate * before replacing the mapentry. 11417c478bd9Sstevel@tonic-gate */ 11427c478bd9Sstevel@tonic-gate if (me->me_dt == DT_QR) 11437c478bd9Sstevel@tonic-gate HANDLE_DQUOT(me, melist); 11447c478bd9Sstevel@tonic-gate 11457c478bd9Sstevel@tonic-gate kmem_cache_free(mapentry_cache, me); 11467c478bd9Sstevel@tonic-gate continue; 11477c478bd9Sstevel@tonic-gate } 11487c478bd9Sstevel@tonic-gate me->me_cancel = mtm->mtm_cancel; 11497c478bd9Sstevel@tonic-gate mtm->mtm_cancel = me; 11507c478bd9Sstevel@tonic-gate me->me_flags |= ME_CANCEL; 11517c478bd9Sstevel@tonic-gate } 11527c478bd9Sstevel@tonic-gate mep = &(*mep)->me_hash; 11537c478bd9Sstevel@tonic-gate } 11547c478bd9Sstevel@tonic-gate mutex_exit(&mtm->mtm_mutex); 11557c478bd9Sstevel@tonic-gate 11567c478bd9Sstevel@tonic-gate /* 11577c478bd9Sstevel@tonic-gate * remove from list 11587c478bd9Sstevel@tonic-gate */ 11597c478bd9Sstevel@tonic-gate me = melist; 11607c478bd9Sstevel@tonic-gate melist = melist->me_hash; 11617c478bd9Sstevel@tonic-gate me->me_flags &= ~ME_LIST; 11627c478bd9Sstevel@tonic-gate /* 11637c478bd9Sstevel@tonic-gate * If va != NULL, put in the log. 11647c478bd9Sstevel@tonic-gate */ 11657c478bd9Sstevel@tonic-gate if (va) 11667c478bd9Sstevel@tonic-gate ldl_write(ul, va, vamof, me); 11677c478bd9Sstevel@tonic-gate if (ul->un_flags & LDL_ERROR) { 11687c478bd9Sstevel@tonic-gate kmem_cache_free(mapentry_cache, me); 11697c478bd9Sstevel@tonic-gate continue; 11707c478bd9Sstevel@tonic-gate } 11717c478bd9Sstevel@tonic-gate ASSERT((va == NULL) || 11727c478bd9Sstevel@tonic-gate ((mtm->mtm_debug & MT_LOG_WRITE_CHECK) == 0) || 11737c478bd9Sstevel@tonic-gate map_check_ldl_write(ul, va, vamof, me)); 11747c478bd9Sstevel@tonic-gate 11757c478bd9Sstevel@tonic-gate /* 11767c478bd9Sstevel@tonic-gate * put on hash 11777c478bd9Sstevel@tonic-gate */ 11787c478bd9Sstevel@tonic-gate mutex_enter(&mtm->mtm_mutex); 11797c478bd9Sstevel@tonic-gate me->me_hash = *savmep; 11807c478bd9Sstevel@tonic-gate *savmep = me; 11817c478bd9Sstevel@tonic-gate me->me_next = (mapentry_t *)mtm; 11827c478bd9Sstevel@tonic-gate me->me_prev = mtm->mtm_prev; 11837c478bd9Sstevel@tonic-gate mtm->mtm_prev->me_next = me; 11847c478bd9Sstevel@tonic-gate mtm->mtm_prev = me; 11857c478bd9Sstevel@tonic-gate me->me_flags |= ME_HASH; 11867c478bd9Sstevel@tonic-gate me->me_tid = tid; 11877c478bd9Sstevel@tonic-gate me->me_age = mtm->mtm_age++; 11887c478bd9Sstevel@tonic-gate mtm->mtm_nme++; 11897c478bd9Sstevel@tonic-gate mtm->mtm_nmet++; 11907c478bd9Sstevel@tonic-gate mutex_exit(&mtm->mtm_mutex); 11917c478bd9Sstevel@tonic-gate } 11927c478bd9Sstevel@tonic-gate 11937c478bd9Sstevel@tonic-gate ASSERT(((mtm->mtm_debug & MT_CHECK_MAP) == 0) || 11947c478bd9Sstevel@tonic-gate map_check_linkage(mtm)); 11957c478bd9Sstevel@tonic-gate mutex_exit(&ul->un_log_mutex); 11967c478bd9Sstevel@tonic-gate } 11977c478bd9Sstevel@tonic-gate 11987c478bd9Sstevel@tonic-gate /* 11997c478bd9Sstevel@tonic-gate * Add the delta(s) into the log. 12007c478bd9Sstevel@tonic-gate * Create one cached roll buffer logmap entry, and reference count the 12017c478bd9Sstevel@tonic-gate * number of mapentries refering to it. 12027c478bd9Sstevel@tonic-gate * Cancel previous logmap entries. 12037c478bd9Sstevel@tonic-gate * logmap_add is tolerant of failure to allocate a cached roll buffer. 12047c478bd9Sstevel@tonic-gate */ 12057c478bd9Sstevel@tonic-gate void 12067c478bd9Sstevel@tonic-gate logmap_add_buf( 12077c478bd9Sstevel@tonic-gate ml_unit_t *ul, 12087c478bd9Sstevel@tonic-gate char *va, /* Ptr to buf w/deltas & data */ 12097c478bd9Sstevel@tonic-gate offset_t bufmof, /* Offset on master of buf start */ 12107c478bd9Sstevel@tonic-gate mapentry_t *melist, /* Entries to add */ 12117c478bd9Sstevel@tonic-gate caddr_t buf, /* Buffer containing delta(s) */ 12127c478bd9Sstevel@tonic-gate uint32_t bufsz) /* Size of buf */ 12137c478bd9Sstevel@tonic-gate { 12147c478bd9Sstevel@tonic-gate offset_t mof; 12157c478bd9Sstevel@tonic-gate offset_t vamof = bufmof + (va - buf); 12167c478bd9Sstevel@tonic-gate off_t nb; 12177c478bd9Sstevel@tonic-gate mapentry_t *me; 12187c478bd9Sstevel@tonic-gate mapentry_t **mep; 12197c478bd9Sstevel@tonic-gate mapentry_t **savmep; 12207c478bd9Sstevel@tonic-gate uint32_t tid; 12217c478bd9Sstevel@tonic-gate mt_map_t *mtm = ul->un_logmap; 12227c478bd9Sstevel@tonic-gate crb_t *crb; 12237c478bd9Sstevel@tonic-gate crb_t *crbsav = NULL; 12247c478bd9Sstevel@tonic-gate 12257c478bd9Sstevel@tonic-gate ASSERT((bufsz & DEV_BMASK) == 0); 12267c478bd9Sstevel@tonic-gate mutex_enter(&ul->un_log_mutex); 12277c478bd9Sstevel@tonic-gate logmap_wait_space(mtm, ul, melist); 12287c478bd9Sstevel@tonic-gate 12297c478bd9Sstevel@tonic-gate ASSERT(((mtm->mtm_debug & MT_CHECK_MAP) == 0) || 12307c478bd9Sstevel@tonic-gate map_check_linkage(mtm)); 12317c478bd9Sstevel@tonic-gate 12327c478bd9Sstevel@tonic-gate mtm->mtm_ref = 1; 12337c478bd9Sstevel@tonic-gate mtm->mtm_dirty++; 12347c478bd9Sstevel@tonic-gate tid = mtm->mtm_tid; 12357c478bd9Sstevel@tonic-gate while (melist) { 12367c478bd9Sstevel@tonic-gate mof = melist->me_mof; 12377c478bd9Sstevel@tonic-gate nb = melist->me_nb; 12387c478bd9Sstevel@tonic-gate 12397c478bd9Sstevel@tonic-gate /* 12407c478bd9Sstevel@tonic-gate * search for overlapping entries 12417c478bd9Sstevel@tonic-gate */ 12427c478bd9Sstevel@tonic-gate savmep = mep = MAP_HASH(mof, mtm); 12437c478bd9Sstevel@tonic-gate mutex_enter(&mtm->mtm_mutex); 12447c478bd9Sstevel@tonic-gate while ((me = *mep) != 0) { 12457c478bd9Sstevel@tonic-gate /* 12467c478bd9Sstevel@tonic-gate * Data consumes old map entry; cancel map entry. 12477c478bd9Sstevel@tonic-gate * Take care when we replace an old map entry 12487c478bd9Sstevel@tonic-gate * which carries quota information with a newer entry 12497c478bd9Sstevel@tonic-gate * which does not. In that case the push function 12507c478bd9Sstevel@tonic-gate * would not be called to clean up the dquot structure. 12517c478bd9Sstevel@tonic-gate * This would be found later by invalidatedq() causing 12527c478bd9Sstevel@tonic-gate * a panic when the filesystem in unmounted. 12537c478bd9Sstevel@tonic-gate * We clean up the dquot manually and then replace 12547c478bd9Sstevel@tonic-gate * the map entry. 12557c478bd9Sstevel@tonic-gate */ 12567c478bd9Sstevel@tonic-gate crb = me->me_crb; 12577c478bd9Sstevel@tonic-gate if (MEwithinDATA(me, mof, nb) && 12587c478bd9Sstevel@tonic-gate ((me->me_flags & (ME_ROLL|ME_CANCEL)) == 0)) { 12597c478bd9Sstevel@tonic-gate if (tid == me->me_tid && 12607c478bd9Sstevel@tonic-gate ((me->me_flags & ME_AGE) == 0)) { 12617c478bd9Sstevel@tonic-gate *mep = me->me_hash; 12627c478bd9Sstevel@tonic-gate me->me_next->me_prev = me->me_prev; 12637c478bd9Sstevel@tonic-gate me->me_prev->me_next = me->me_next; 12647c478bd9Sstevel@tonic-gate ASSERT(!(me->me_flags & ME_USER)); 12657c478bd9Sstevel@tonic-gate mtm->mtm_nme--; 12667c478bd9Sstevel@tonic-gate /* 12677c478bd9Sstevel@tonic-gate * Special case if the mapentry 12687c478bd9Sstevel@tonic-gate * carries a dquot and a push function. 12697c478bd9Sstevel@tonic-gate * We have to clean up the quota info 12707c478bd9Sstevel@tonic-gate * before replacing the mapentry. 12717c478bd9Sstevel@tonic-gate */ 12727c478bd9Sstevel@tonic-gate if (me->me_dt == DT_QR) 12737c478bd9Sstevel@tonic-gate HANDLE_DQUOT(me, melist); 12747c478bd9Sstevel@tonic-gate 12757c478bd9Sstevel@tonic-gate /* 12767c478bd9Sstevel@tonic-gate * If this soon to be deleted mapentry 12777c478bd9Sstevel@tonic-gate * has a suitable roll buffer then 12787c478bd9Sstevel@tonic-gate * re-use it. 12797c478bd9Sstevel@tonic-gate */ 12807c478bd9Sstevel@tonic-gate if (crb && (--crb->c_refcnt == 0)) { 12817c478bd9Sstevel@tonic-gate if (crbsav || 12827c478bd9Sstevel@tonic-gate (crb->c_nb != bufsz)) { 12837c478bd9Sstevel@tonic-gate CRB_FREE(crb, me); 12847c478bd9Sstevel@tonic-gate } else { 12857c478bd9Sstevel@tonic-gate bcopy(buf, crb->c_buf, 12867c478bd9Sstevel@tonic-gate bufsz); 12877c478bd9Sstevel@tonic-gate crb->c_invalid = 0; 12887c478bd9Sstevel@tonic-gate crb->c_mof = bufmof; 12897c478bd9Sstevel@tonic-gate crbsav = crb; 12907c478bd9Sstevel@tonic-gate me->me_crb = NULL; 12917c478bd9Sstevel@tonic-gate } 12927c478bd9Sstevel@tonic-gate } 12937c478bd9Sstevel@tonic-gate kmem_cache_free(mapentry_cache, me); 12947c478bd9Sstevel@tonic-gate continue; 12957c478bd9Sstevel@tonic-gate } 12967c478bd9Sstevel@tonic-gate me->me_cancel = mtm->mtm_cancel; 12977c478bd9Sstevel@tonic-gate mtm->mtm_cancel = me; 12987c478bd9Sstevel@tonic-gate me->me_flags |= ME_CANCEL; 12997c478bd9Sstevel@tonic-gate } 13007c478bd9Sstevel@tonic-gate 13017c478bd9Sstevel@tonic-gate /* 13027c478bd9Sstevel@tonic-gate * Inode deltas within the same fs block come 13037c478bd9Sstevel@tonic-gate * in individually as separate calls to logmap_add(). 13047c478bd9Sstevel@tonic-gate * All others come in as one call. So check for an 13057c478bd9Sstevel@tonic-gate * existing entry where we can re-use the crb. 13067c478bd9Sstevel@tonic-gate */ 13077c478bd9Sstevel@tonic-gate if ((me->me_dt == DT_INODE) && (tid == me->me_tid) && 13087c478bd9Sstevel@tonic-gate !crbsav && crb && 13097c478bd9Sstevel@tonic-gate WITHIN(mof, nb, crb->c_mof, crb->c_nb)) { 13107c478bd9Sstevel@tonic-gate ASSERT(crb->c_mof == bufmof); 13117c478bd9Sstevel@tonic-gate ASSERT(crb->c_nb == bufsz); 13127c478bd9Sstevel@tonic-gate bcopy(buf, crb->c_buf, bufsz); 13137c478bd9Sstevel@tonic-gate crbsav = crb; 13147c478bd9Sstevel@tonic-gate } 13157c478bd9Sstevel@tonic-gate mep = &(*mep)->me_hash; 13167c478bd9Sstevel@tonic-gate } 13177c478bd9Sstevel@tonic-gate mutex_exit(&mtm->mtm_mutex); 13187c478bd9Sstevel@tonic-gate 13197c478bd9Sstevel@tonic-gate /* 13207c478bd9Sstevel@tonic-gate * If we don't already have a crb then allocate one 13217c478bd9Sstevel@tonic-gate * and copy the incoming buffer. Only do this once 13227c478bd9Sstevel@tonic-gate * for all the incoming deltas. 13237c478bd9Sstevel@tonic-gate */ 13247c478bd9Sstevel@tonic-gate if ((crbsav == NULL) && (melist->me_dt != DT_ABZERO)) { 13257c478bd9Sstevel@tonic-gate /* 13267c478bd9Sstevel@tonic-gate * Only use a cached roll buffer if we 13277c478bd9Sstevel@tonic-gate * have enough memory, and check for failures. 13287c478bd9Sstevel@tonic-gate */ 13297c478bd9Sstevel@tonic-gate if (((ufs_crb_size + bufsz) < ufs_crb_limit) && 13307c478bd9Sstevel@tonic-gate (kmem_avail() > bufsz)) { 13317c478bd9Sstevel@tonic-gate crbsav = kmem_alloc(sizeof (crb_t), KM_NOSLEEP); 13327c478bd9Sstevel@tonic-gate } else { 13337c478bd9Sstevel@tonic-gate ufs_crb_alloc_fails++; 13347c478bd9Sstevel@tonic-gate } 13357c478bd9Sstevel@tonic-gate if (crbsav) { 13367c478bd9Sstevel@tonic-gate crbsav->c_buf = kmem_alloc(bufsz, KM_NOSLEEP); 13377c478bd9Sstevel@tonic-gate if (crbsav->c_buf) { 13387c478bd9Sstevel@tonic-gate atomic_add_64(&ufs_crb_size, 13397c478bd9Sstevel@tonic-gate (uint64_t)bufsz); 13407c478bd9Sstevel@tonic-gate if (ufs_crb_size > ufs_crb_max_size) { 13417c478bd9Sstevel@tonic-gate ufs_crb_max_size = ufs_crb_size; 13427c478bd9Sstevel@tonic-gate } 13437c478bd9Sstevel@tonic-gate bcopy(buf, crbsav->c_buf, bufsz); 13447c478bd9Sstevel@tonic-gate crbsav->c_nb = bufsz; 13457c478bd9Sstevel@tonic-gate crbsav->c_refcnt = 0; 13467c478bd9Sstevel@tonic-gate crbsav->c_invalid = 0; 13477c478bd9Sstevel@tonic-gate ASSERT((bufmof & DEV_BMASK) == 0); 13487c478bd9Sstevel@tonic-gate crbsav->c_mof = bufmof; 13497c478bd9Sstevel@tonic-gate } else { 13507c478bd9Sstevel@tonic-gate kmem_free(crbsav, sizeof (crb_t)); 13517c478bd9Sstevel@tonic-gate crbsav = NULL; 13527c478bd9Sstevel@tonic-gate } 13537c478bd9Sstevel@tonic-gate } 13547c478bd9Sstevel@tonic-gate } 13557c478bd9Sstevel@tonic-gate 13567c478bd9Sstevel@tonic-gate /* 13577c478bd9Sstevel@tonic-gate * remove from list 13587c478bd9Sstevel@tonic-gate */ 13597c478bd9Sstevel@tonic-gate me = melist; 13607c478bd9Sstevel@tonic-gate melist = melist->me_hash; 13617c478bd9Sstevel@tonic-gate me->me_flags &= ~ME_LIST; 13627c478bd9Sstevel@tonic-gate me->me_crb = crbsav; 13637c478bd9Sstevel@tonic-gate if (crbsav) { 13647c478bd9Sstevel@tonic-gate crbsav->c_refcnt++; 13657c478bd9Sstevel@tonic-gate } 13667c478bd9Sstevel@tonic-gate crbsav = NULL; 13677c478bd9Sstevel@tonic-gate 13687c478bd9Sstevel@tonic-gate ASSERT(va); 13697c478bd9Sstevel@tonic-gate ldl_write(ul, va, vamof, me); /* add to on-disk log */ 13707c478bd9Sstevel@tonic-gate if (ul->un_flags & LDL_ERROR) { 13717c478bd9Sstevel@tonic-gate CRB_RELE(me); 13727c478bd9Sstevel@tonic-gate kmem_cache_free(mapentry_cache, me); 13737c478bd9Sstevel@tonic-gate continue; 13747c478bd9Sstevel@tonic-gate } 13757c478bd9Sstevel@tonic-gate ASSERT(((mtm->mtm_debug & MT_LOG_WRITE_CHECK) == 0) || 13767c478bd9Sstevel@tonic-gate map_check_ldl_write(ul, va, vamof, me)); 13777c478bd9Sstevel@tonic-gate 13787c478bd9Sstevel@tonic-gate /* 13797c478bd9Sstevel@tonic-gate * put on hash 13807c478bd9Sstevel@tonic-gate */ 13817c478bd9Sstevel@tonic-gate mutex_enter(&mtm->mtm_mutex); 13827c478bd9Sstevel@tonic-gate me->me_hash = *savmep; 13837c478bd9Sstevel@tonic-gate *savmep = me; 13847c478bd9Sstevel@tonic-gate me->me_next = (mapentry_t *)mtm; 13857c478bd9Sstevel@tonic-gate me->me_prev = mtm->mtm_prev; 13867c478bd9Sstevel@tonic-gate mtm->mtm_prev->me_next = me; 13877c478bd9Sstevel@tonic-gate mtm->mtm_prev = me; 13887c478bd9Sstevel@tonic-gate me->me_flags |= ME_HASH; 13897c478bd9Sstevel@tonic-gate me->me_tid = tid; 13907c478bd9Sstevel@tonic-gate me->me_age = mtm->mtm_age++; 13917c478bd9Sstevel@tonic-gate mtm->mtm_nme++; 13927c478bd9Sstevel@tonic-gate mtm->mtm_nmet++; 13937c478bd9Sstevel@tonic-gate mutex_exit(&mtm->mtm_mutex); 13947c478bd9Sstevel@tonic-gate } 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate ASSERT(((mtm->mtm_debug & MT_CHECK_MAP) == 0) || 13977c478bd9Sstevel@tonic-gate map_check_linkage(mtm)); 13987c478bd9Sstevel@tonic-gate mutex_exit(&ul->un_log_mutex); 13997c478bd9Sstevel@tonic-gate } 14007c478bd9Sstevel@tonic-gate 14017c478bd9Sstevel@tonic-gate /* 14027c478bd9Sstevel@tonic-gate * free up any cancelled deltas 14037c478bd9Sstevel@tonic-gate */ 14047c478bd9Sstevel@tonic-gate void 14057c478bd9Sstevel@tonic-gate logmap_free_cancel(mt_map_t *mtm, mapentry_t **cancelhead) 14067c478bd9Sstevel@tonic-gate { 14077c478bd9Sstevel@tonic-gate int dolock = 0; 14087c478bd9Sstevel@tonic-gate mapentry_t *me; 14097c478bd9Sstevel@tonic-gate mapentry_t **mep; 14107c478bd9Sstevel@tonic-gate 14117c478bd9Sstevel@tonic-gate ASSERT(((mtm->mtm_debug & MT_CHECK_MAP) == 0) || 14127c478bd9Sstevel@tonic-gate map_check_linkage(mtm)); 14137c478bd9Sstevel@tonic-gate 14147c478bd9Sstevel@tonic-gate again: 14157c478bd9Sstevel@tonic-gate if (dolock) 14167c478bd9Sstevel@tonic-gate rw_enter(&mtm->mtm_rwlock, RW_WRITER); 14177c478bd9Sstevel@tonic-gate 14187c478bd9Sstevel@tonic-gate /* 14197c478bd9Sstevel@tonic-gate * At EOT, cancel the indicated deltas 14207c478bd9Sstevel@tonic-gate */ 14217c478bd9Sstevel@tonic-gate mutex_enter(&mtm->mtm_mutex); 14227c478bd9Sstevel@tonic-gate if (mtm->mtm_flags & MTM_CANCELED) { 14237c478bd9Sstevel@tonic-gate mtm->mtm_flags &= ~MTM_CANCELED; 14247c478bd9Sstevel@tonic-gate ASSERT(dolock == 0); 14257c478bd9Sstevel@tonic-gate mutex_exit(&mtm->mtm_mutex); 14267c478bd9Sstevel@tonic-gate return; 14277c478bd9Sstevel@tonic-gate } 14287c478bd9Sstevel@tonic-gate 14297c478bd9Sstevel@tonic-gate while ((me = *cancelhead) != NULL) { 14307c478bd9Sstevel@tonic-gate /* 14317c478bd9Sstevel@tonic-gate * roll forward or read collision; wait and try again 14327c478bd9Sstevel@tonic-gate */ 14337c478bd9Sstevel@tonic-gate if (me->me_flags & ME_AGE) { 14347c478bd9Sstevel@tonic-gate ASSERT(dolock == 0); 14357c478bd9Sstevel@tonic-gate mutex_exit(&mtm->mtm_mutex); 14367c478bd9Sstevel@tonic-gate dolock = 1; 14377c478bd9Sstevel@tonic-gate goto again; 14387c478bd9Sstevel@tonic-gate } 14397c478bd9Sstevel@tonic-gate /* 14407c478bd9Sstevel@tonic-gate * remove from cancel list 14417c478bd9Sstevel@tonic-gate */ 14427c478bd9Sstevel@tonic-gate *cancelhead = me->me_cancel; 14437c478bd9Sstevel@tonic-gate me->me_cancel = NULL; 14447c478bd9Sstevel@tonic-gate me->me_flags &= ~(ME_CANCEL); 14457c478bd9Sstevel@tonic-gate 14467c478bd9Sstevel@tonic-gate /* 14477c478bd9Sstevel@tonic-gate * logmap_remove_roll handles ME_ROLL entries later 14487c478bd9Sstevel@tonic-gate * we leave them around for logmap_iscancel 14497c478bd9Sstevel@tonic-gate * XXX is this necessary? 14507c478bd9Sstevel@tonic-gate */ 14517c478bd9Sstevel@tonic-gate if (me->me_flags & ME_ROLL) 14527c478bd9Sstevel@tonic-gate continue; 14537c478bd9Sstevel@tonic-gate 14547c478bd9Sstevel@tonic-gate /* 14557c478bd9Sstevel@tonic-gate * remove from hash (if necessary) 14567c478bd9Sstevel@tonic-gate */ 14577c478bd9Sstevel@tonic-gate if (me->me_flags & ME_HASH) { 14587c478bd9Sstevel@tonic-gate mep = MAP_HASH(me->me_mof, mtm); 14597c478bd9Sstevel@tonic-gate while (*mep) { 14607c478bd9Sstevel@tonic-gate if (*mep == me) { 14617c478bd9Sstevel@tonic-gate *mep = me->me_hash; 14627c478bd9Sstevel@tonic-gate me->me_next->me_prev = me->me_prev; 14637c478bd9Sstevel@tonic-gate me->me_prev->me_next = me->me_next; 14647c478bd9Sstevel@tonic-gate me->me_flags &= ~(ME_HASH); 14657c478bd9Sstevel@tonic-gate if (!(me->me_flags & ME_USER)) { 14667c478bd9Sstevel@tonic-gate mtm->mtm_nme--; 14677c478bd9Sstevel@tonic-gate } 14687c478bd9Sstevel@tonic-gate break; 14697c478bd9Sstevel@tonic-gate } else 14707c478bd9Sstevel@tonic-gate mep = &(*mep)->me_hash; 14717c478bd9Sstevel@tonic-gate } 14727c478bd9Sstevel@tonic-gate } 14737c478bd9Sstevel@tonic-gate /* 14747c478bd9Sstevel@tonic-gate * put the entry on the free list 14757c478bd9Sstevel@tonic-gate */ 14767c478bd9Sstevel@tonic-gate CRB_RELE(me); 14777c478bd9Sstevel@tonic-gate kmem_cache_free(mapentry_cache, me); 14787c478bd9Sstevel@tonic-gate } 14797c478bd9Sstevel@tonic-gate mutex_exit(&mtm->mtm_mutex); 14807c478bd9Sstevel@tonic-gate if (dolock) 14817c478bd9Sstevel@tonic-gate rw_exit(&mtm->mtm_rwlock); 14827c478bd9Sstevel@tonic-gate 14837c478bd9Sstevel@tonic-gate ASSERT(((mtm->mtm_debug & MT_CHECK_MAP) == 0) || 14847c478bd9Sstevel@tonic-gate map_check_linkage(mtm)); 14857c478bd9Sstevel@tonic-gate } 14867c478bd9Sstevel@tonic-gate 14877c478bd9Sstevel@tonic-gate 14887c478bd9Sstevel@tonic-gate void 14897c478bd9Sstevel@tonic-gate logmap_commit(ml_unit_t *ul, uint32_t tid) 14907c478bd9Sstevel@tonic-gate { 14917c478bd9Sstevel@tonic-gate mapentry_t me; 14927c478bd9Sstevel@tonic-gate mt_map_t *mtm = ul->un_logmap; 14937c478bd9Sstevel@tonic-gate 14947c478bd9Sstevel@tonic-gate 14957c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ul->un_log_mutex)); 14967c478bd9Sstevel@tonic-gate 14977c478bd9Sstevel@tonic-gate /* 14987c478bd9Sstevel@tonic-gate * async'ly write a commit rec into the log 14997c478bd9Sstevel@tonic-gate */ 15007c478bd9Sstevel@tonic-gate if (mtm->mtm_dirty) { 15017c478bd9Sstevel@tonic-gate /* 15027c478bd9Sstevel@tonic-gate * put commit record into log 15037c478bd9Sstevel@tonic-gate */ 15047c478bd9Sstevel@tonic-gate me.me_mof = mtm->mtm_tid; 15057c478bd9Sstevel@tonic-gate me.me_dt = DT_COMMIT; 15067c478bd9Sstevel@tonic-gate me.me_nb = 0; 15077c478bd9Sstevel@tonic-gate me.me_hash = NULL; 15087c478bd9Sstevel@tonic-gate logmap_wait_space(mtm, ul, &me); 15097c478bd9Sstevel@tonic-gate ldl_write(ul, NULL, (offset_t)0, &me); 15107c478bd9Sstevel@tonic-gate ldl_round_commit(ul); 15117c478bd9Sstevel@tonic-gate 15127c478bd9Sstevel@tonic-gate /* 15137c478bd9Sstevel@tonic-gate * abort on error; else reset dirty flag 15147c478bd9Sstevel@tonic-gate */ 15157c478bd9Sstevel@tonic-gate if (ul->un_flags & LDL_ERROR) 15167c478bd9Sstevel@tonic-gate logmap_abort(ul, tid); 15177c478bd9Sstevel@tonic-gate else { 15187c478bd9Sstevel@tonic-gate mtm->mtm_dirty = 0; 15197c478bd9Sstevel@tonic-gate mtm->mtm_nmet = 0; 15207c478bd9Sstevel@tonic-gate mtm->mtm_cfrags = 0; 15217c478bd9Sstevel@tonic-gate } 15227c478bd9Sstevel@tonic-gate /* push commit */ 15237c478bd9Sstevel@tonic-gate ldl_push_commit(ul); 15247c478bd9Sstevel@tonic-gate } 15257c478bd9Sstevel@tonic-gate } 15267c478bd9Sstevel@tonic-gate 15277c478bd9Sstevel@tonic-gate void 15287c478bd9Sstevel@tonic-gate logmap_sethead(mt_map_t *mtm, ml_unit_t *ul) 15297c478bd9Sstevel@tonic-gate { 15307c478bd9Sstevel@tonic-gate off_t lof; 15317c478bd9Sstevel@tonic-gate uint32_t tid; 15327c478bd9Sstevel@tonic-gate mapentry_t *me; 15337c478bd9Sstevel@tonic-gate 15347c478bd9Sstevel@tonic-gate /* 15357c478bd9Sstevel@tonic-gate * move the head forward so the log knows how full it is 15367c478bd9Sstevel@tonic-gate * Make sure to skip any mapentry whose me_lof is 0, these 15377c478bd9Sstevel@tonic-gate * are just place holders for DT_CANCELED freed user blocks 15387c478bd9Sstevel@tonic-gate * for the current moby. 15397c478bd9Sstevel@tonic-gate */ 15407c478bd9Sstevel@tonic-gate mutex_enter(&ul->un_log_mutex); 15417c478bd9Sstevel@tonic-gate mutex_enter(&mtm->mtm_mutex); 15427c478bd9Sstevel@tonic-gate me = mtm->mtm_next; 15437c478bd9Sstevel@tonic-gate while (me != (mapentry_t *)mtm && me->me_lof == 0) { 15447c478bd9Sstevel@tonic-gate me = me->me_next; 15457c478bd9Sstevel@tonic-gate } 15467c478bd9Sstevel@tonic-gate 15477c478bd9Sstevel@tonic-gate if (me == (mapentry_t *)mtm) 15487c478bd9Sstevel@tonic-gate lof = -1; 15497c478bd9Sstevel@tonic-gate else { 15507c478bd9Sstevel@tonic-gate lof = me->me_lof; 15517c478bd9Sstevel@tonic-gate tid = me->me_tid; 15527c478bd9Sstevel@tonic-gate } 15537c478bd9Sstevel@tonic-gate mutex_exit(&mtm->mtm_mutex); 15547c478bd9Sstevel@tonic-gate ldl_sethead(ul, lof, tid); 15557c478bd9Sstevel@tonic-gate if (lof == -1) 15567c478bd9Sstevel@tonic-gate mtm->mtm_age = 0; 15577c478bd9Sstevel@tonic-gate mutex_exit(&ul->un_log_mutex); 15587c478bd9Sstevel@tonic-gate } 15597c478bd9Sstevel@tonic-gate 15607c478bd9Sstevel@tonic-gate void 15617c478bd9Sstevel@tonic-gate logmap_settail(mt_map_t *mtm, ml_unit_t *ul) 15627c478bd9Sstevel@tonic-gate { 15637c478bd9Sstevel@tonic-gate off_t lof; 15647c478bd9Sstevel@tonic-gate size_t nb; 15657c478bd9Sstevel@tonic-gate 15667c478bd9Sstevel@tonic-gate /* 15677c478bd9Sstevel@tonic-gate * set the tail after the logmap_abort 15687c478bd9Sstevel@tonic-gate */ 15697c478bd9Sstevel@tonic-gate mutex_enter(&ul->un_log_mutex); 15707c478bd9Sstevel@tonic-gate mutex_enter(&mtm->mtm_mutex); 15717c478bd9Sstevel@tonic-gate if (mtm->mtm_prev == (mapentry_t *)mtm) 15727c478bd9Sstevel@tonic-gate lof = -1; 15737c478bd9Sstevel@tonic-gate else { 15747c478bd9Sstevel@tonic-gate /* 15757c478bd9Sstevel@tonic-gate * set the tail to the end of the last commit 15767c478bd9Sstevel@tonic-gate */ 15777c478bd9Sstevel@tonic-gate lof = mtm->mtm_tail_lof; 15787c478bd9Sstevel@tonic-gate nb = mtm->mtm_tail_nb; 15797c478bd9Sstevel@tonic-gate } 15807c478bd9Sstevel@tonic-gate mutex_exit(&mtm->mtm_mutex); 15817c478bd9Sstevel@tonic-gate ldl_settail(ul, lof, nb); 15827c478bd9Sstevel@tonic-gate mutex_exit(&ul->un_log_mutex); 15837c478bd9Sstevel@tonic-gate } 15847c478bd9Sstevel@tonic-gate 15857c478bd9Sstevel@tonic-gate /* 15867c478bd9Sstevel@tonic-gate * when reseting a device; roll the log until every 15877c478bd9Sstevel@tonic-gate * delta has been rolled forward 15887c478bd9Sstevel@tonic-gate */ 15897c478bd9Sstevel@tonic-gate void 15907c478bd9Sstevel@tonic-gate logmap_roll_dev(ml_unit_t *ul) 15917c478bd9Sstevel@tonic-gate { 15927c478bd9Sstevel@tonic-gate mt_map_t *mtm = ul->un_logmap; 15937c478bd9Sstevel@tonic-gate mapentry_t *me; 15947c478bd9Sstevel@tonic-gate ufsvfs_t *ufsvfsp = ul->un_ufsvfs; 15957c478bd9Sstevel@tonic-gate 15967c478bd9Sstevel@tonic-gate again: 15977c478bd9Sstevel@tonic-gate ASSERT(((mtm->mtm_debug & MT_CHECK_MAP) == 0) || 15987c478bd9Sstevel@tonic-gate map_check_linkage(mtm)); 15997c478bd9Sstevel@tonic-gate if (ul->un_flags & (LDL_ERROR|LDL_NOROLL)) 16007c478bd9Sstevel@tonic-gate return; 16017c478bd9Sstevel@tonic-gate 16027c478bd9Sstevel@tonic-gate /* 16037c478bd9Sstevel@tonic-gate * look for deltas 16047c478bd9Sstevel@tonic-gate */ 16057c478bd9Sstevel@tonic-gate mutex_enter(&mtm->mtm_mutex); 16067c478bd9Sstevel@tonic-gate for (me = mtm->mtm_next; me != (mapentry_t *)mtm; me = me->me_next) { 16077c478bd9Sstevel@tonic-gate if (me->me_flags & ME_ROLL) 16087c478bd9Sstevel@tonic-gate break; 16097c478bd9Sstevel@tonic-gate if (me->me_tid == mtm->mtm_tid) 16107c478bd9Sstevel@tonic-gate continue; 16117c478bd9Sstevel@tonic-gate if (me->me_tid == mtm->mtm_committid) 16127c478bd9Sstevel@tonic-gate continue; 16137c478bd9Sstevel@tonic-gate break; 16147c478bd9Sstevel@tonic-gate } 16157c478bd9Sstevel@tonic-gate 16167c478bd9Sstevel@tonic-gate /* 16177c478bd9Sstevel@tonic-gate * found a delta; kick the roll thread 16187c478bd9Sstevel@tonic-gate * but only if the thread is running... (jmh) 16197c478bd9Sstevel@tonic-gate */ 16207c478bd9Sstevel@tonic-gate if (me != (mapentry_t *)mtm) { 16217c478bd9Sstevel@tonic-gate mutex_exit(&mtm->mtm_mutex); 16227c478bd9Sstevel@tonic-gate logmap_forceroll(mtm); 16237c478bd9Sstevel@tonic-gate goto again; 16247c478bd9Sstevel@tonic-gate } 16257c478bd9Sstevel@tonic-gate 16267c478bd9Sstevel@tonic-gate /* 16277c478bd9Sstevel@tonic-gate * no more deltas, return 16287c478bd9Sstevel@tonic-gate */ 16297c478bd9Sstevel@tonic-gate mutex_exit(&mtm->mtm_mutex); 16307c478bd9Sstevel@tonic-gate (void) ufs_putsummaryinfo(ul->un_dev, ufsvfsp, ufsvfsp->vfs_fs); 16317c478bd9Sstevel@tonic-gate 16327c478bd9Sstevel@tonic-gate ASSERT(((mtm->mtm_debug & MT_CHECK_MAP) == 0) || 16337c478bd9Sstevel@tonic-gate map_check_linkage(mtm)); 16347c478bd9Sstevel@tonic-gate } 16357c478bd9Sstevel@tonic-gate 16367c478bd9Sstevel@tonic-gate static void 16377c478bd9Sstevel@tonic-gate logmap_cancel_delta(ml_unit_t *ul, offset_t mof, int32_t nb, int metadata) 16387c478bd9Sstevel@tonic-gate { 16397c478bd9Sstevel@tonic-gate mapentry_t *me; 16407c478bd9Sstevel@tonic-gate mapentry_t **mep; 16417c478bd9Sstevel@tonic-gate mt_map_t *mtm = ul->un_logmap; 16427c478bd9Sstevel@tonic-gate int frags; 16437c478bd9Sstevel@tonic-gate 16447c478bd9Sstevel@tonic-gate /* 16457c478bd9Sstevel@tonic-gate * map has been referenced and is dirty 16467c478bd9Sstevel@tonic-gate */ 16477c478bd9Sstevel@tonic-gate mtm->mtm_ref = 1; 16487c478bd9Sstevel@tonic-gate mtm->mtm_dirty++; 16497c478bd9Sstevel@tonic-gate 16507c478bd9Sstevel@tonic-gate /* 16517c478bd9Sstevel@tonic-gate * get a mapentry 16527c478bd9Sstevel@tonic-gate */ 16537c478bd9Sstevel@tonic-gate me = kmem_cache_alloc(mapentry_cache, KM_SLEEP); 16547c478bd9Sstevel@tonic-gate bzero(me, sizeof (mapentry_t)); 16557c478bd9Sstevel@tonic-gate 16567c478bd9Sstevel@tonic-gate /* 16577c478bd9Sstevel@tonic-gate * initialize cancel record and put in logmap 16587c478bd9Sstevel@tonic-gate */ 16597c478bd9Sstevel@tonic-gate me->me_mof = mof; 16607c478bd9Sstevel@tonic-gate me->me_nb = nb; 16617c478bd9Sstevel@tonic-gate me->me_dt = DT_CANCEL; 16627c478bd9Sstevel@tonic-gate me->me_tid = mtm->mtm_tid; 16637c478bd9Sstevel@tonic-gate me->me_hash = NULL; 16647c478bd9Sstevel@tonic-gate 16657c478bd9Sstevel@tonic-gate /* 16667c478bd9Sstevel@tonic-gate * Write delta to log if this delta is for metadata. If this is not 16677c478bd9Sstevel@tonic-gate * metadata it is user data and we are just putting a cancel 16687c478bd9Sstevel@tonic-gate * mapentry into the hash to cancel a user block deletion 16697c478bd9Sstevel@tonic-gate * in which we do not want the block to be allocated 16707c478bd9Sstevel@tonic-gate * within this moby. This cancel entry will prevent the block from 16717c478bd9Sstevel@tonic-gate * being allocated within the moby and prevent user data corruption 16727c478bd9Sstevel@tonic-gate * if we happen to crash before this moby is committed. 16737c478bd9Sstevel@tonic-gate */ 16747c478bd9Sstevel@tonic-gate mutex_enter(&ul->un_log_mutex); 16757c478bd9Sstevel@tonic-gate if (metadata) { 16767c478bd9Sstevel@tonic-gate logmap_wait_space(mtm, ul, me); 16777c478bd9Sstevel@tonic-gate ldl_write(ul, NULL, (offset_t)0, me); 16787c478bd9Sstevel@tonic-gate if (ul->un_flags & LDL_ERROR) { 16797c478bd9Sstevel@tonic-gate kmem_cache_free(mapentry_cache, me); 16807c478bd9Sstevel@tonic-gate mutex_exit(&ul->un_log_mutex); 16817c478bd9Sstevel@tonic-gate return; 16827c478bd9Sstevel@tonic-gate } 16837c478bd9Sstevel@tonic-gate } 16847c478bd9Sstevel@tonic-gate 16857c478bd9Sstevel@tonic-gate /* 16867c478bd9Sstevel@tonic-gate * put in hash and on cancel list 16877c478bd9Sstevel@tonic-gate */ 16887c478bd9Sstevel@tonic-gate mep = MAP_HASH(mof, mtm); 16897c478bd9Sstevel@tonic-gate mutex_enter(&mtm->mtm_mutex); 16907c478bd9Sstevel@tonic-gate me->me_age = mtm->mtm_age++; 16917c478bd9Sstevel@tonic-gate me->me_hash = *mep; 16927c478bd9Sstevel@tonic-gate *mep = me; 16937c478bd9Sstevel@tonic-gate me->me_next = (mapentry_t *)mtm; 16947c478bd9Sstevel@tonic-gate me->me_prev = mtm->mtm_prev; 16957c478bd9Sstevel@tonic-gate mtm->mtm_prev->me_next = me; 16967c478bd9Sstevel@tonic-gate mtm->mtm_prev = me; 16977c478bd9Sstevel@tonic-gate me->me_cancel = mtm->mtm_cancel; 16987c478bd9Sstevel@tonic-gate mtm->mtm_cancel = me; 16997c478bd9Sstevel@tonic-gate if (metadata) { 17007c478bd9Sstevel@tonic-gate mtm->mtm_nme++; 17017c478bd9Sstevel@tonic-gate mtm->mtm_nmet++; 17027c478bd9Sstevel@tonic-gate } else { 17037c478bd9Sstevel@tonic-gate me->me_flags = ME_USER; 17047c478bd9Sstevel@tonic-gate } 17057c478bd9Sstevel@tonic-gate me->me_flags |= (ME_HASH|ME_CANCEL); 17067c478bd9Sstevel@tonic-gate if (!(metadata)) { 17077c478bd9Sstevel@tonic-gate frags = blkoff(ul->un_ufsvfs->vfs_fs, nb); 17087c478bd9Sstevel@tonic-gate if (frags) 170980d34432Sfrankho mtm->mtm_cfrags += 171080d34432Sfrankho numfrags(ul->un_ufsvfs->vfs_fs, frags); 17117c478bd9Sstevel@tonic-gate } 17127c478bd9Sstevel@tonic-gate mutex_exit(&mtm->mtm_mutex); 17137c478bd9Sstevel@tonic-gate 17147c478bd9Sstevel@tonic-gate mutex_exit(&ul->un_log_mutex); 17157c478bd9Sstevel@tonic-gate } 17167c478bd9Sstevel@tonic-gate 17177c478bd9Sstevel@tonic-gate /* 17187c478bd9Sstevel@tonic-gate * cancel entries in a logmap (entries are freed at EOT) 17197c478bd9Sstevel@tonic-gate */ 17207c478bd9Sstevel@tonic-gate void 17217c478bd9Sstevel@tonic-gate logmap_cancel(ml_unit_t *ul, offset_t mof, off_t nb, int metadata) 17227c478bd9Sstevel@tonic-gate { 17237c478bd9Sstevel@tonic-gate int32_t hnb; 17247c478bd9Sstevel@tonic-gate mapentry_t *me; 17257c478bd9Sstevel@tonic-gate mapentry_t **mep; 17267c478bd9Sstevel@tonic-gate mt_map_t *mtm = ul->un_logmap; 17277c478bd9Sstevel@tonic-gate crb_t *crb; 17287c478bd9Sstevel@tonic-gate 17297c478bd9Sstevel@tonic-gate ASSERT(((mtm->mtm_debug & MT_CHECK_MAP) == 0) || 17307c478bd9Sstevel@tonic-gate map_check_linkage(mtm)); 17317c478bd9Sstevel@tonic-gate 17327c478bd9Sstevel@tonic-gate for (hnb = 0; nb; nb -= hnb, mof += hnb) { 17337c478bd9Sstevel@tonic-gate hnb = MAPBLOCKSIZE - (mof & MAPBLOCKOFF); 17347c478bd9Sstevel@tonic-gate if (hnb > nb) 17357c478bd9Sstevel@tonic-gate hnb = nb; 17367c478bd9Sstevel@tonic-gate /* 173720a1ae8aSjkennedy * Find overlapping metadata entries. Don't search through 173820a1ae8aSjkennedy * the hash chains if this is user data because it is only 173920a1ae8aSjkennedy * possible to have overlapping map entries for metadata, 174020a1ae8aSjkennedy * and the search can become expensive for large files. 17417c478bd9Sstevel@tonic-gate */ 174220a1ae8aSjkennedy if (metadata) { 17437c478bd9Sstevel@tonic-gate mep = MAP_HASH(mof, mtm); 17447c478bd9Sstevel@tonic-gate mutex_enter(&mtm->mtm_mutex); 17457c478bd9Sstevel@tonic-gate for (me = *mep; me; me = me->me_hash) { 17467c478bd9Sstevel@tonic-gate if (!DATAoverlapME(mof, hnb, me)) 17477c478bd9Sstevel@tonic-gate continue; 17487c478bd9Sstevel@tonic-gate 17497c478bd9Sstevel@tonic-gate ASSERT(MEwithinDATA(me, mof, hnb)); 17507c478bd9Sstevel@tonic-gate 17517c478bd9Sstevel@tonic-gate if ((me->me_flags & ME_CANCEL) == 0) { 17527c478bd9Sstevel@tonic-gate me->me_cancel = mtm->mtm_cancel; 17537c478bd9Sstevel@tonic-gate mtm->mtm_cancel = me; 17547c478bd9Sstevel@tonic-gate me->me_flags |= ME_CANCEL; 17557c478bd9Sstevel@tonic-gate crb = me->me_crb; 17567c478bd9Sstevel@tonic-gate if (crb) { 17577c478bd9Sstevel@tonic-gate crb->c_invalid = 1; 17587c478bd9Sstevel@tonic-gate } 17597c478bd9Sstevel@tonic-gate } 17607c478bd9Sstevel@tonic-gate } 17617c478bd9Sstevel@tonic-gate mutex_exit(&mtm->mtm_mutex); 176220a1ae8aSjkennedy } 17637c478bd9Sstevel@tonic-gate 17647c478bd9Sstevel@tonic-gate /* 17657c478bd9Sstevel@tonic-gate * put a cancel record into the log 17667c478bd9Sstevel@tonic-gate */ 17677c478bd9Sstevel@tonic-gate logmap_cancel_delta(ul, mof, hnb, metadata); 17687c478bd9Sstevel@tonic-gate } 17697c478bd9Sstevel@tonic-gate 17707c478bd9Sstevel@tonic-gate ASSERT(((mtm->mtm_debug & MT_CHECK_MAP) == 0) || 17717c478bd9Sstevel@tonic-gate map_check_linkage(mtm)); 17727c478bd9Sstevel@tonic-gate } 17737c478bd9Sstevel@tonic-gate 17747c478bd9Sstevel@tonic-gate /* 17757c478bd9Sstevel@tonic-gate * check for overlap w/cancel delta 17767c478bd9Sstevel@tonic-gate */ 17777c478bd9Sstevel@tonic-gate int 17787c478bd9Sstevel@tonic-gate logmap_iscancel(mt_map_t *mtm, offset_t mof, off_t nb) 17797c478bd9Sstevel@tonic-gate { 17807c478bd9Sstevel@tonic-gate off_t hnb; 17817c478bd9Sstevel@tonic-gate mapentry_t *me; 17827c478bd9Sstevel@tonic-gate mapentry_t **mep; 17837c478bd9Sstevel@tonic-gate 17847c478bd9Sstevel@tonic-gate mutex_enter(&mtm->mtm_mutex); 17857c478bd9Sstevel@tonic-gate for (hnb = 0; nb; nb -= hnb, mof += hnb) { 17867c478bd9Sstevel@tonic-gate hnb = MAPBLOCKSIZE - (mof & MAPBLOCKOFF); 17877c478bd9Sstevel@tonic-gate if (hnb > nb) 17887c478bd9Sstevel@tonic-gate hnb = nb; 17897c478bd9Sstevel@tonic-gate /* 17907c478bd9Sstevel@tonic-gate * search for dup entry 17917c478bd9Sstevel@tonic-gate */ 17927c478bd9Sstevel@tonic-gate mep = MAP_HASH(mof, mtm); 17937c478bd9Sstevel@tonic-gate for (me = *mep; me; me = me->me_hash) { 17947c478bd9Sstevel@tonic-gate if (((me->me_flags & ME_ROLL) == 0) && 17957c478bd9Sstevel@tonic-gate (me->me_dt != DT_CANCEL)) 17967c478bd9Sstevel@tonic-gate continue; 17977c478bd9Sstevel@tonic-gate if (DATAoverlapME(mof, hnb, me)) 17987c478bd9Sstevel@tonic-gate break; 17997c478bd9Sstevel@tonic-gate } 18007c478bd9Sstevel@tonic-gate 18017c478bd9Sstevel@tonic-gate /* 18027c478bd9Sstevel@tonic-gate * overlap detected 18037c478bd9Sstevel@tonic-gate */ 18047c478bd9Sstevel@tonic-gate if (me) { 18057c478bd9Sstevel@tonic-gate mutex_exit(&mtm->mtm_mutex); 18067c478bd9Sstevel@tonic-gate return (1); 18077c478bd9Sstevel@tonic-gate } 18087c478bd9Sstevel@tonic-gate } 18097c478bd9Sstevel@tonic-gate mutex_exit(&mtm->mtm_mutex); 18107c478bd9Sstevel@tonic-gate return (0); 18117c478bd9Sstevel@tonic-gate } 18127c478bd9Sstevel@tonic-gate 18137c478bd9Sstevel@tonic-gate static int 18147c478bd9Sstevel@tonic-gate logmap_logscan_add(ml_unit_t *ul, struct delta *dp, off_t lof, size_t *nbp) 18157c478bd9Sstevel@tonic-gate { 18167c478bd9Sstevel@tonic-gate mapentry_t *me; 18177c478bd9Sstevel@tonic-gate int error; 18187c478bd9Sstevel@tonic-gate mt_map_t *mtm = ul->un_logmap; 18197c478bd9Sstevel@tonic-gate 18207c478bd9Sstevel@tonic-gate /* 18217c478bd9Sstevel@tonic-gate * verify delta header; failure == mediafail 18227c478bd9Sstevel@tonic-gate */ 18237c478bd9Sstevel@tonic-gate error = 0; 18247c478bd9Sstevel@tonic-gate /* delta type */ 18257c478bd9Sstevel@tonic-gate if ((dp->d_typ <= DT_NONE) || (dp->d_typ >= DT_MAX)) 18267c478bd9Sstevel@tonic-gate error = EINVAL; 18277c478bd9Sstevel@tonic-gate if (dp->d_typ == DT_COMMIT) { 18287c478bd9Sstevel@tonic-gate if (dp->d_nb != INT32_C(0) && dp->d_nb != INT32_C(-1)) 18297c478bd9Sstevel@tonic-gate error = EINVAL; 18307c478bd9Sstevel@tonic-gate } else { 18317c478bd9Sstevel@tonic-gate /* length of delta */ 18327c478bd9Sstevel@tonic-gate if ((dp->d_nb < INT32_C(0)) || 18337c478bd9Sstevel@tonic-gate (dp->d_nb > INT32_C(MAPBLOCKSIZE))) 18347c478bd9Sstevel@tonic-gate error = EINVAL; 18357c478bd9Sstevel@tonic-gate 18367c478bd9Sstevel@tonic-gate /* offset on master device */ 18377c478bd9Sstevel@tonic-gate if (dp->d_mof < INT64_C(0)) 18387c478bd9Sstevel@tonic-gate error = EINVAL; 18397c478bd9Sstevel@tonic-gate } 18407c478bd9Sstevel@tonic-gate 18417c478bd9Sstevel@tonic-gate if (error) { 18427c478bd9Sstevel@tonic-gate ldl_seterror(ul, "Error processing ufs log data during scan"); 18437c478bd9Sstevel@tonic-gate return (error); 18447c478bd9Sstevel@tonic-gate } 18457c478bd9Sstevel@tonic-gate 18467c478bd9Sstevel@tonic-gate /* 18477c478bd9Sstevel@tonic-gate * process commit record 18487c478bd9Sstevel@tonic-gate */ 18497c478bd9Sstevel@tonic-gate if (dp->d_typ == DT_COMMIT) { 18507c478bd9Sstevel@tonic-gate if (mtm->mtm_dirty) { 18517c478bd9Sstevel@tonic-gate ASSERT(dp->d_nb == INT32_C(0)); 18527c478bd9Sstevel@tonic-gate logmap_free_cancel(mtm, &mtm->mtm_cancel); 18537c478bd9Sstevel@tonic-gate mtm->mtm_dirty = 0; 18547c478bd9Sstevel@tonic-gate mtm->mtm_nmet = 0; 18557c478bd9Sstevel@tonic-gate mtm->mtm_tid++; 18567c478bd9Sstevel@tonic-gate mtm->mtm_committid = mtm->mtm_tid; 18577c478bd9Sstevel@tonic-gate ASSERT(((mtm->mtm_debug & MT_SCAN) == 0) || 18587c478bd9Sstevel@tonic-gate logmap_logscan_commit_debug(lof, mtm)); 18597c478bd9Sstevel@tonic-gate } 18607c478bd9Sstevel@tonic-gate /* 18617c478bd9Sstevel@tonic-gate * return #bytes to next sector (next delta header) 18627c478bd9Sstevel@tonic-gate */ 18637c478bd9Sstevel@tonic-gate *nbp = ldl_logscan_nbcommit(lof); 18647c478bd9Sstevel@tonic-gate mtm->mtm_tail_lof = lof; 18657c478bd9Sstevel@tonic-gate mtm->mtm_tail_nb = *nbp; 18667c478bd9Sstevel@tonic-gate return (0); 18677c478bd9Sstevel@tonic-gate } 18687c478bd9Sstevel@tonic-gate 18697c478bd9Sstevel@tonic-gate /* 18707c478bd9Sstevel@tonic-gate * add delta to logmap 18717c478bd9Sstevel@tonic-gate */ 18727c478bd9Sstevel@tonic-gate me = kmem_cache_alloc(mapentry_cache, KM_SLEEP); 18737c478bd9Sstevel@tonic-gate bzero(me, sizeof (mapentry_t)); 18747c478bd9Sstevel@tonic-gate me->me_lof = lof; 18757c478bd9Sstevel@tonic-gate me->me_mof = dp->d_mof; 18767c478bd9Sstevel@tonic-gate me->me_nb = dp->d_nb; 18777c478bd9Sstevel@tonic-gate me->me_tid = mtm->mtm_tid; 18787c478bd9Sstevel@tonic-gate me->me_dt = dp->d_typ; 18797c478bd9Sstevel@tonic-gate me->me_hash = NULL; 18807c478bd9Sstevel@tonic-gate me->me_flags = (ME_LIST | ME_SCAN); 18817c478bd9Sstevel@tonic-gate logmap_add(ul, NULL, 0, me); 18827c478bd9Sstevel@tonic-gate switch (dp->d_typ) { 18837c478bd9Sstevel@tonic-gate case DT_CANCEL: 18847c478bd9Sstevel@tonic-gate me->me_flags |= ME_CANCEL; 18857c478bd9Sstevel@tonic-gate me->me_cancel = mtm->mtm_cancel; 18867c478bd9Sstevel@tonic-gate mtm->mtm_cancel = me; 18877c478bd9Sstevel@tonic-gate break; 18887c478bd9Sstevel@tonic-gate default: 18897c478bd9Sstevel@tonic-gate ASSERT(((mtm->mtm_debug & MT_SCAN) == 0) || 18907c478bd9Sstevel@tonic-gate logmap_logscan_add_debug(dp, mtm)); 18917c478bd9Sstevel@tonic-gate break; 18927c478bd9Sstevel@tonic-gate } 18937c478bd9Sstevel@tonic-gate 18947c478bd9Sstevel@tonic-gate sizeofdelta: 18957c478bd9Sstevel@tonic-gate /* 18967c478bd9Sstevel@tonic-gate * return #bytes till next delta header 18977c478bd9Sstevel@tonic-gate */ 18987c478bd9Sstevel@tonic-gate if ((dp->d_typ == DT_CANCEL) || (dp->d_typ == DT_ABZERO)) 18997c478bd9Sstevel@tonic-gate *nbp = 0; 19007c478bd9Sstevel@tonic-gate else 19017c478bd9Sstevel@tonic-gate *nbp = dp->d_nb; 19027c478bd9Sstevel@tonic-gate return (0); 19037c478bd9Sstevel@tonic-gate } 19047c478bd9Sstevel@tonic-gate 19057c478bd9Sstevel@tonic-gate void 19067c478bd9Sstevel@tonic-gate logmap_logscan(ml_unit_t *ul) 19077c478bd9Sstevel@tonic-gate { 19087c478bd9Sstevel@tonic-gate size_t nb, nbd; 19097c478bd9Sstevel@tonic-gate off_t lof; 19107c478bd9Sstevel@tonic-gate struct delta delta; 19117c478bd9Sstevel@tonic-gate mt_map_t *logmap = ul->un_logmap; 19127c478bd9Sstevel@tonic-gate 19137c478bd9Sstevel@tonic-gate ASSERT(ul->un_deltamap->mtm_next == (mapentry_t *)ul->un_deltamap); 19147c478bd9Sstevel@tonic-gate 19157c478bd9Sstevel@tonic-gate /* 19167c478bd9Sstevel@tonic-gate * prepare the log for a logscan 19177c478bd9Sstevel@tonic-gate */ 19187c478bd9Sstevel@tonic-gate ldl_logscan_begin(ul); 19197c478bd9Sstevel@tonic-gate 19207c478bd9Sstevel@tonic-gate /* 19217c478bd9Sstevel@tonic-gate * prepare the logmap for a logscan 19227c478bd9Sstevel@tonic-gate */ 19237c478bd9Sstevel@tonic-gate (void) map_free_entries(logmap); 19247c478bd9Sstevel@tonic-gate logmap->mtm_tid = 0; 19257c478bd9Sstevel@tonic-gate logmap->mtm_committid = UINT32_C(0); 19267c478bd9Sstevel@tonic-gate logmap->mtm_age = 0; 19277c478bd9Sstevel@tonic-gate logmap->mtm_dirty = 0; 19287c478bd9Sstevel@tonic-gate logmap->mtm_ref = 0; 19297c478bd9Sstevel@tonic-gate 19307c478bd9Sstevel@tonic-gate /* 19317c478bd9Sstevel@tonic-gate * while not at end of log 19327c478bd9Sstevel@tonic-gate * read delta header 19337c478bd9Sstevel@tonic-gate * add to logmap 19347c478bd9Sstevel@tonic-gate * seek to beginning of next delta 19357c478bd9Sstevel@tonic-gate */ 19367c478bd9Sstevel@tonic-gate lof = ul->un_head_lof; 19377c478bd9Sstevel@tonic-gate nbd = sizeof (delta); 19387c478bd9Sstevel@tonic-gate while (lof != ul->un_tail_lof) { 19397c478bd9Sstevel@tonic-gate 19407c478bd9Sstevel@tonic-gate /* read delta header */ 19417c478bd9Sstevel@tonic-gate if (ldl_logscan_read(ul, &lof, nbd, (caddr_t)&delta)) 19427c478bd9Sstevel@tonic-gate break; 19437c478bd9Sstevel@tonic-gate 19447c478bd9Sstevel@tonic-gate /* add to logmap */ 19457c478bd9Sstevel@tonic-gate if (logmap_logscan_add(ul, &delta, lof, &nb)) 19467c478bd9Sstevel@tonic-gate break; 19477c478bd9Sstevel@tonic-gate 19487c478bd9Sstevel@tonic-gate /* seek to next header (skip data) */ 19497c478bd9Sstevel@tonic-gate if (ldl_logscan_read(ul, &lof, nb, NULL)) 19507c478bd9Sstevel@tonic-gate break; 19517c478bd9Sstevel@tonic-gate } 19527c478bd9Sstevel@tonic-gate 19537c478bd9Sstevel@tonic-gate /* 19547c478bd9Sstevel@tonic-gate * remove the last partial transaction from the logmap 19557c478bd9Sstevel@tonic-gate */ 19567c478bd9Sstevel@tonic-gate logmap_abort(ul, logmap->mtm_tid); 19577c478bd9Sstevel@tonic-gate 19587c478bd9Sstevel@tonic-gate ldl_logscan_end(ul); 19597c478bd9Sstevel@tonic-gate } 19607c478bd9Sstevel@tonic-gate 19617c478bd9Sstevel@tonic-gate void 19627c478bd9Sstevel@tonic-gate _init_map(void) 19637c478bd9Sstevel@tonic-gate { 19647c478bd9Sstevel@tonic-gate /* 19657c478bd9Sstevel@tonic-gate * Initialise the mapentry cache. No constructor or deconstructor 19667c478bd9Sstevel@tonic-gate * is needed. Also no reclaim function is supplied as reclaiming 19677c478bd9Sstevel@tonic-gate * current entries is not possible. 19687c478bd9Sstevel@tonic-gate */ 19697c478bd9Sstevel@tonic-gate mapentry_cache = kmem_cache_create("lufs_mapentry_cache", 19707c478bd9Sstevel@tonic-gate sizeof (mapentry_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 19717c478bd9Sstevel@tonic-gate } 19727c478bd9Sstevel@tonic-gate 19737c478bd9Sstevel@tonic-gate /* 19747c478bd9Sstevel@tonic-gate * Special case when we replace an old map entry which carries quota 19757c478bd9Sstevel@tonic-gate * information with a newer entry which does not. 19767c478bd9Sstevel@tonic-gate * In that case the push function would not be called to clean up the 19777c478bd9Sstevel@tonic-gate * dquot structure. This would be found later by invalidatedq() causing 19787c478bd9Sstevel@tonic-gate * a panic when the filesystem in unmounted. 19797c478bd9Sstevel@tonic-gate * We clean up the dquot manually before replacing the map entry. 19807c478bd9Sstevel@tonic-gate */ 19817c478bd9Sstevel@tonic-gate void 19827c478bd9Sstevel@tonic-gate handle_dquot(mapentry_t *me) 19837c478bd9Sstevel@tonic-gate { 19847c478bd9Sstevel@tonic-gate int dolock = 0; 19857c478bd9Sstevel@tonic-gate int domutex = 0; 19867c478bd9Sstevel@tonic-gate struct dquot *dqp; 19877c478bd9Sstevel@tonic-gate 19887c478bd9Sstevel@tonic-gate dqp = (struct dquot *)me->me_arg; 19897c478bd9Sstevel@tonic-gate 19907c478bd9Sstevel@tonic-gate /* 19917c478bd9Sstevel@tonic-gate * We need vfs_dqrwlock to call dqput() 19927c478bd9Sstevel@tonic-gate */ 19937c478bd9Sstevel@tonic-gate dolock = (!RW_LOCK_HELD(&dqp->dq_ufsvfsp->vfs_dqrwlock)); 19947c478bd9Sstevel@tonic-gate if (dolock) 19957c478bd9Sstevel@tonic-gate rw_enter(&dqp->dq_ufsvfsp->vfs_dqrwlock, RW_READER); 19967c478bd9Sstevel@tonic-gate 19977c478bd9Sstevel@tonic-gate domutex = (!MUTEX_HELD(&dqp->dq_lock)); 19987c478bd9Sstevel@tonic-gate if (domutex) 19997c478bd9Sstevel@tonic-gate mutex_enter(&dqp->dq_lock); 20007c478bd9Sstevel@tonic-gate 20017c478bd9Sstevel@tonic-gate /* 20027c478bd9Sstevel@tonic-gate * Only clean up if the dquot is referenced 20037c478bd9Sstevel@tonic-gate */ 20047c478bd9Sstevel@tonic-gate if (dqp->dq_cnt == 0) { 20057c478bd9Sstevel@tonic-gate if (domutex) 20067c478bd9Sstevel@tonic-gate mutex_exit(&dqp->dq_lock); 20077c478bd9Sstevel@tonic-gate if (dolock) 20087c478bd9Sstevel@tonic-gate rw_exit(&dqp->dq_ufsvfsp->vfs_dqrwlock); 20097c478bd9Sstevel@tonic-gate return; 20107c478bd9Sstevel@tonic-gate } 20117c478bd9Sstevel@tonic-gate 20127c478bd9Sstevel@tonic-gate dqp->dq_flags &= ~(DQ_MOD|DQ_TRANS); 20137c478bd9Sstevel@tonic-gate dqput(dqp); 20147c478bd9Sstevel@tonic-gate 20157c478bd9Sstevel@tonic-gate if (domutex) 20167c478bd9Sstevel@tonic-gate mutex_exit(&dqp->dq_lock); 20177c478bd9Sstevel@tonic-gate 20187c478bd9Sstevel@tonic-gate if (dolock) 20197c478bd9Sstevel@tonic-gate rw_exit(&dqp->dq_ufsvfsp->vfs_dqrwlock); 20207c478bd9Sstevel@tonic-gate 20217c478bd9Sstevel@tonic-gate } 2022