X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/e5568f75972dfc723778653c11cb6b4dc825716a..c18c124eaa464aaaa5549e99e5a70fc9cbb50944:/bsd/hfs/hfs_hotfiles.c diff --git a/bsd/hfs/hfs_hotfiles.c b/bsd/hfs/hfs_hotfiles.c index e5f94cd64..7ba80c737 100644 --- a/bsd/hfs/hfs_hotfiles.c +++ b/bsd/hfs/hfs_hotfiles.c @@ -1,23 +1,29 @@ /* - * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2003-2013 Apple Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. * - * @APPLE_LICENSE_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ #include @@ -26,7 +32,10 @@ #include #include #include +#include #include +#include +#include #include #include @@ -41,6 +50,11 @@ #define HFC_VERBOSE 0 +/* + * Minimum post Tiger base time. + * Thu Mar 31 17:00:00 2005 + */ +#define HFC_MIN_BASE_TIME 0x424c8f00L /* * Hot File List (runtime). @@ -90,6 +104,8 @@ typedef struct hotfile_data { hotfile_entry_t entries[1]; } hotfile_data_t; +static int hfs_recording_start (struct hfsmount *); +static int hfs_recording_stop (struct hfsmount *); /* @@ -97,26 +113,32 @@ typedef struct hotfile_data { */ static void hf_insert (hotfile_data_t *, hotfile_entry_t *); static void hf_delete (hotfile_data_t *, u_int32_t, u_int32_t); -static hotfile_entry_t * hf_lookup (hotfile_data_t *, u_int32_t, u_int32_t); static hotfile_entry_t * hf_coldest (hotfile_data_t *); static hotfile_entry_t * hf_getnewentry (hotfile_data_t *); -static int hf_getsortedlist (hotfile_data_t *, hotfilelist_t *); -static void hf_printtree (hotfile_entry_t *); +static void hf_getsortedlist (hotfile_data_t *, hotfilelist_t *); + +#if HFC_DEBUG +static hotfile_entry_t * hf_lookup (hotfile_data_t *, u_int32_t, u_int32_t); +static void hf_maxdepth(hotfile_entry_t *, int, int *); +static void hf_printtree (hotfile_entry_t *); +#endif /* * Hot File misc support functions. */ -static int hotfiles_collect (struct hfsmount *, struct proc *); -static int hotfiles_age (struct hfsmount *, struct proc *); -static int hotfiles_adopt (struct hfsmount *, struct proc *); -static int hotfiles_evict (struct hfsmount *, struct proc *); -static int hotfiles_refine (struct hfsmount *, struct proc *); +static int hotfiles_collect (struct hfsmount *); +static int hotfiles_age (struct hfsmount *); +static int hotfiles_adopt (struct hfsmount *); +static int hotfiles_evict (struct hfsmount *, vfs_context_t); +static int hotfiles_refine (struct hfsmount *); static int hotextents(struct hfsmount *, HFSPlusExtentDescriptor *); +static int hfs_addhotfile_internal(struct vnode *); + /* * Hot File Cluster B-tree (on disk) functions. */ -static int hfc_btree_create (struct hfsmount *, int, int); +static int hfc_btree_create (struct hfsmount *, unsigned int, unsigned int); static int hfc_btree_open (struct hfsmount *, struct vnode **); static int hfc_btree_close (struct hfsmount *, struct vnode *); static int hfc_comparekeys (HotFileKey *, HotFileKey *); @@ -134,12 +156,13 @@ char hfc_tag[] = "CLUSTERED HOT FILES B-TREE "; /* * Start recording the hotest files on a file system. * + * Requires that the hfc_mutex be held. */ -__private_extern__ -int -hfs_recording_start(struct hfsmount *hfsmp, struct proc *p) +static int +hfs_recording_start(struct hfsmount *hfsmp) { hotfile_data_t *hotdata; + struct timeval tv; int maxentries; size_t size; int i; @@ -150,7 +173,7 @@ hfs_recording_start(struct hfsmount *hfsmp, struct proc *p) (hfsmp->hfs_flags & HFS_METADATA_ZONE) == 0) { return (EPERM); } - if (HFSTOVCB(hfsmp)->freeBlocks < (2 * hfsmp->hfs_hotfile_maxblks)) { + if (HFSTOVCB(hfsmp)->freeBlocks < (2 * (u_int32_t)hfsmp->hfs_hotfile_maxblks)) { return (ENOSPC); } if (hfsmp->hfc_stage != HFC_IDLE) { @@ -169,6 +192,8 @@ hfs_recording_start(struct hfsmount *hfsmp, struct proc *p) FREE(tmp, M_TEMP); } + microtime(&tv); /* Times are base on GMT time. */ + /* * On first startup check for suspended recording. */ @@ -182,14 +207,19 @@ hfs_recording_start(struct hfsmount *hfsmp, struct proc *p) (SWAP_BE32 (hotfileinfo.timeleft) > 0) && (SWAP_BE32 (hotfileinfo.timebase) > 0)) { hfsmp->hfc_maxfiles = SWAP_BE32 (hotfileinfo.maxfilecnt); - hfsmp->hfc_timeout = SWAP_BE32 (hotfileinfo.timeleft) + time.tv_sec ; hfsmp->hfc_timebase = SWAP_BE32 (hotfileinfo.timebase); + hfsmp->hfc_timeout = SWAP_BE32 (hotfileinfo.timeleft) + tv.tv_sec ; + /* Fix up any bogus timebase values. */ + if (hfsmp->hfc_timebase < HFC_MIN_BASE_TIME) { + hfsmp->hfc_timebase = hfsmp->hfc_timeout - HFC_DEFAULT_DURATION; + } #if HFC_VERBOSE - printf("HFS: resume recording hot files (%d left)\n", SWAP_BE32 (hotfileinfo.timeleft)); + printf("hfs: Resume recording hot files on %s (%d secs left)\n", + hfsmp->vcbVN, SWAP_BE32 (hotfileinfo.timeleft)); #endif } else { hfsmp->hfc_maxfiles = HFC_DEFAULT_FILE_COUNT; - hfsmp->hfc_timebase = time.tv_sec + 1; + hfsmp->hfc_timebase = tv.tv_sec + 1; hfsmp->hfc_timeout = hfsmp->hfc_timebase + HFC_DEFAULT_DURATION; } (void) hfc_btree_close(hfsmp, hfsmp->hfc_filevp); @@ -210,17 +240,16 @@ hfs_recording_start(struct hfsmount *hfsmp, struct proc *p) return (error); } #if HFC_VERBOSE - printf("HFS: begin recording hot files\n"); + printf("hfs: begin recording hot files on %s\n", hfsmp->vcbVN); #endif hfsmp->hfc_maxfiles = HFC_DEFAULT_FILE_COUNT; - hfsmp->hfc_timeout = time.tv_sec + HFC_DEFAULT_DURATION; + hfsmp->hfc_timeout = tv.tv_sec + HFC_DEFAULT_DURATION; /* Reset time base. */ if (hfsmp->hfc_timebase == 0) { - hfsmp->hfc_timebase = time.tv_sec + 1; + hfsmp->hfc_timebase = tv.tv_sec + 1; } else { - u_int32_t cumulativebase; - u_int32_t oldbase = hfsmp->hfc_timebase; + time_t cumulativebase; cumulativebase = hfsmp->hfc_timeout - (HFC_CUMULATIVE_CYCLES * HFC_DEFAULT_DURATION); hfsmp->hfc_timebase = MAX(hfsmp->hfc_timebase, cumulativebase); @@ -235,6 +264,13 @@ hfs_recording_start(struct hfsmount *hfsmp, struct proc *p) size = sizeof(hotfile_data_t) + (maxentries * sizeof(hotfile_entry_t)); MALLOC(hotdata, hotfile_data_t *, size, M_TEMP, M_WAITOK); + if (hotdata == NULL) { + hfsmp->hfc_recdata = NULL; + hfsmp->hfc_stage = HFC_IDLE; + wakeup((caddr_t)&hfsmp->hfc_stage); + return(ENOMEM); + } + bzero(hotdata, size); for (i = 1; i < maxentries ; i++) @@ -249,7 +285,6 @@ hfs_recording_start(struct hfsmount *hfsmp, struct proc *p) hotdata->hfsmp = hfsmp; hfsmp->hfc_recdata = hotdata; -out: hfsmp->hfc_stage = HFC_RECORDING; wakeup((caddr_t)&hfsmp->hfc_stage); return (0); @@ -257,28 +292,26 @@ out: /* * Stop recording the hotest files on a file system. + * + * Requires that the hfc_mutex be held. */ -__private_extern__ -int -hfs_recording_stop(struct hfsmount *hfsmp, struct proc *p) +static int +hfs_recording_stop(struct hfsmount *hfsmp) { hotfile_data_t *hotdata; hotfilelist_t *listp; + struct timeval tv; size_t size; enum hfc_stage newstage = HFC_IDLE; - void * tmp; int error; - if (hfsmp->hfc_stage != HFC_RECORDING) return (EPERM); - hotfiles_collect(hfsmp, p); + hfsmp->hfc_stage = HFC_BUSY; - if (hfsmp->hfc_stage != HFC_RECORDING) - return (0); + hotfiles_collect(hfsmp); - hfsmp->hfc_stage = HFC_BUSY; /* * Convert hot file data into a simple file id list.... @@ -286,7 +319,7 @@ hfs_recording_stop(struct hfsmount *hfsmp, struct proc *p) * then dump the sample data */ #if HFC_VERBOSE - printf("HFS: end of hot file recording\n"); + printf("hfs: end of hot file recording on %s\n", hfsmp->vcbVN); #endif hotdata = (hotfile_data_t *)hfsmp->hfc_recdata; if (hotdata == NULL) @@ -296,7 +329,7 @@ hfs_recording_stop(struct hfsmount *hfsmp, struct proc *p) wakeup((caddr_t)&hfsmp->hfc_stage); #if HFC_VERBOSE - printf(" curentries: %d\n", hotdata->activefiles); + printf("hfs: curentries: %d\n", hotdata->activefiles); #endif /* * If no hot files recorded then we're done. @@ -308,7 +341,7 @@ hfs_recording_stop(struct hfsmount *hfsmp, struct proc *p) /* Open the B-tree file for writing... */ if (hfsmp->hfc_filevp) - panic("hfs_recording_stop: hfc_filevp exists (vp = 0x%08x)", hfsmp->hfc_filevp); + panic("hfs_recording_stop: hfc_filevp exists (vp = %p)", hfsmp->hfc_filevp); error = hfc_btree_open(hfsmp, &hfsmp->hfc_filevp); if (error) { @@ -318,7 +351,7 @@ hfs_recording_stop(struct hfsmount *hfsmp, struct proc *p) /* * Age the previous set of clustered hot files. */ - error = hotfiles_age(hfsmp, p); + error = hotfiles_age(hfsmp); if (error) { (void) hfc_btree_close(hfsmp, hfsmp->hfc_filevp); hfsmp->hfc_filevp = NULL; @@ -331,16 +364,24 @@ hfs_recording_stop(struct hfsmount *hfsmp, struct proc *p) size = sizeof(hotfilelist_t); size += sizeof(hotfileinfo_t) * (hotdata->activefiles - 1); MALLOC(listp, hotfilelist_t *, size, M_TEMP, M_WAITOK); + if (listp == NULL) { + error = ENOMEM; + (void) hfc_btree_close(hfsmp, hfsmp->hfc_filevp); + hfsmp->hfc_filevp = NULL; + goto out; + } + bzero(listp, size); - hf_getsortedlist(hotdata, listp); - listp->hfl_duration = time.tv_sec - hfsmp->hfc_timebase; + hf_getsortedlist(hotdata, listp); /* NOTE: destroys hot file tree! */ + microtime(&tv); + listp->hfl_duration = tv.tv_sec - hfsmp->hfc_timebase; hfsmp->hfc_recdata = listp; /* * Account for duplicates. */ - error = hotfiles_refine(hfsmp, p); + error = hotfiles_refine(hfsmp); if (error) { (void) hfc_btree_close(hfsmp, hfsmp->hfc_filevp); hfsmp->hfc_filevp = NULL; @@ -373,9 +414,9 @@ hfs_recording_stop(struct hfsmount *hfsmp, struct proc *p) out: #if HFC_VERBOSE if (newstage == HFC_EVICTION) - printf("HFS: evicting coldest files\n"); + printf("hfs: evicting coldest files\n"); else if (newstage == HFC_ADOPTION) - printf("HFS: adopting hotest files\n"); + printf("hfs: adopting hotest files\n"); #endif FREE(hotdata, M_TEMP); @@ -387,26 +428,35 @@ out: /* * Suspend recording the hotest files on a file system. */ -__private_extern__ int -hfs_recording_suspend(struct hfsmount *hfsmp, struct proc *p) +hfs_recording_suspend(struct hfsmount *hfsmp) { HotFilesInfo hotfileinfo; - hotfile_data_t *hotdata; + hotfile_data_t *hotdata = NULL; + struct timeval tv; int error; - if (hfsmp->hfc_stage != HFC_RECORDING) + if (hfsmp->hfc_stage == HFC_DISABLED) return (0); + lck_mtx_lock(&hfsmp->hfc_mutex); + + /* + * XXX NOTE + * A suspend can occur during eval/evict/adopt stage. + * In that case we would need to write out info and + * flush our HFBT vnode. Currently we just bail. + */ + hotdata = (hotfile_data_t *)hfsmp->hfc_recdata; - if (hotdata == NULL) { - hfsmp->hfc_stage = HFC_DISABLED; - return (0); + if (hotdata == NULL || hfsmp->hfc_stage != HFC_RECORDING) { + error = 0; + goto out; } hfsmp->hfc_stage = HFC_BUSY; #if HFC_VERBOSE - printf("HFS: suspend hot file recording\n"); + printf("hfs: suspend hot file recording on %s\n", hfsmp->vcbVN); #endif error = hfc_btree_open(hfsmp, &hfsmp->hfc_filevp); if (error) { @@ -414,85 +464,61 @@ hfs_recording_suspend(struct hfsmount *hfsmp, struct proc *p) goto out; } - hfs_global_shared_lock_acquire(hfsmp); - if (hfsmp->jnl) { - if (journal_start_transaction(hfsmp->jnl) != 0) { - hfs_global_shared_lock_release(hfsmp); - error = EINVAL; - goto out; - } + if (hfs_start_transaction(hfsmp) != 0) { + error = EINVAL; + goto out; + } + if (hfs_lock(VTOC(hfsmp->hfc_filevp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT) != 0) { + error = EPERM; + goto end_transaction; } - vn_lock(hfsmp->hfc_filevp, LK_EXCLUSIVE | LK_RETRY, p); + microtime(&tv); hotfileinfo.magic = SWAP_BE32 (HFC_MAGIC); hotfileinfo.version = SWAP_BE32 (HFC_VERSION); hotfileinfo.duration = SWAP_BE32 (HFC_DEFAULT_DURATION); hotfileinfo.timebase = SWAP_BE32 (hfsmp->hfc_timebase); - hotfileinfo.timeleft = SWAP_BE32 (hfsmp->hfc_timeout - time.tv_sec); + hotfileinfo.timeleft = SWAP_BE32 (hfsmp->hfc_timeout - tv.tv_sec); hotfileinfo.threshold = SWAP_BE32 (hotdata->threshold); hotfileinfo.maxfileblks = SWAP_BE32 (hotdata->maxblocks); hotfileinfo.maxfilecnt = SWAP_BE32 (HFC_DEFAULT_FILE_COUNT); - strcpy(hotfileinfo.tag, hfc_tag); + strlcpy((char *)hotfileinfo.tag, hfc_tag, sizeof hotfileinfo.tag); (void) BTSetUserData(VTOF(hfsmp->hfc_filevp), &hotfileinfo, sizeof(hotfileinfo)); - (void) VOP_UNLOCK(hfsmp->hfc_filevp, 0, p); - if (hfsmp->jnl) { - journal_end_transaction(hfsmp->jnl); - } - hfs_global_shared_lock_release(hfsmp); - - (void) hfc_btree_close(hfsmp, hfsmp->hfc_filevp); - hfsmp->hfc_filevp = NULL; -out: - FREE(hotdata, M_TEMP); + hfs_unlock(VTOC(hfsmp->hfc_filevp)); - hfsmp->hfc_stage = HFC_DISABLED; - wakeup((caddr_t)&hfsmp->hfc_stage); - return (error); -} +end_transaction: + hfs_end_transaction(hfsmp); -/* - * Abort a hot file recording session. - */ -__private_extern__ -int -hfs_recording_abort(struct hfsmount *hfsmp, struct proc *p) -{ - void * tmp; - - if (hfsmp->hfc_stage == HFC_DISABLED) - return (0); - - if (hfsmp->hfc_stage == HFC_BUSY) { - (void) tsleep((caddr_t)&hfsmp->hfc_stage, PINOD, "hfs_recording_abort", 0); +out: + if (hfsmp->hfc_filevp) { + (void) hfc_btree_close(hfsmp, hfsmp->hfc_filevp); + hfsmp->hfc_filevp = NULL; } - hfsmp->hfc_stage = HFC_BUSY; - - printf("HFS: terminate hot file recording\n"); - - if (hfsmp->hfc_recdata) { - tmp = hfsmp->hfc_recdata; + if (hotdata) { + FREE(hotdata, M_TEMP); hfsmp->hfc_recdata = NULL; - FREE(tmp, M_TEMP); } hfsmp->hfc_stage = HFC_DISABLED; wakeup((caddr_t)&hfsmp->hfc_stage); - return (0); + + lck_mtx_unlock(&hfsmp->hfc_mutex); + return (error); } + /* * */ -__private_extern__ int -hfs_recording_init(struct hfsmount *hfsmp, struct proc *p) +hfs_recording_init(struct hfsmount *hfsmp) { CatalogKey * keyp; CatalogRecord * datap; u_int32_t dataSize; HFSPlusCatalogFile *filep; BTScanState scanstate; - BTreeIterator * iterator; + BTreeIterator * iterator = NULL; FSBufferDescriptor record; HotFileKey * key; filefork_t * filefork; @@ -504,6 +530,24 @@ hfs_recording_init(struct hfsmount *hfsmp, struct proc *p) int inserted = 0; /* debug variables */ int filecount = 0; + /* + * For now, only the boot volume is supported. + */ + if ((vfs_flags(HFSTOVFS(hfsmp)) & MNT_ROOTFS) == 0) { + hfsmp->hfc_stage = HFC_DISABLED; + return (EPERM); + } + + /* + * Tracking of hot files requires up-to-date access times. + * So if access time updates are disabled, then we disable + * hot files, too. + */ + if (vfs_flags(HFSTOVFS(hfsmp)) & MNT_NOATIME) { + hfsmp->hfc_stage = HFC_DISABLED; + return EPERM; + } + /* * If the Hot File btree exists then metadata zone is ready. */ @@ -513,27 +557,37 @@ hfs_recording_init(struct hfsmount *hfsmp, struct proc *p) hfsmp->hfc_stage = HFC_IDLE; return (0); } - /* - * For now, only the boot volume is supported. - */ - if ((HFSTOVFS(hfsmp)->mnt_flag & MNT_ROOTFS) == 0) { - hfsmp->hfs_flags &= ~HFS_METADATA_ZONE; - return (EPERM); + + if (hfs_start_transaction(hfsmp) != 0) { + return EINVAL; } + error = hfc_btree_create(hfsmp, HFSTOVCB(hfsmp)->blockSize, HFC_DEFAULT_FILE_COUNT); if (error) { - return (error); +#if HFC_VERBOSE + printf("hfs: Error %d creating hot file b-tree on %s \n", error, hfsmp->vcbVN); +#endif + goto out2; } /* * Open the Hot File B-tree file for writing. */ if (hfsmp->hfc_filevp) - panic("hfs_recording_init: hfc_filevp exists (vp = 0x%08x)", hfsmp->hfc_filevp); + panic("hfs_recording_init: hfc_filevp exists (vp = %p)", hfsmp->hfc_filevp); error = hfc_btree_open(hfsmp, &hfsmp->hfc_filevp); if (error) { - return (error); +#if HFC_VERBOSE + printf("hfs: Error %d opening hot file b-tree on %s \n", error, hfsmp->vcbVN); +#endif + goto out2; } MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK); + if (iterator == NULL) { + error = ENOMEM; + (void) hfc_btree_close(hfsmp, hfsmp->hfc_filevp); + hfsmp->hfc_filevp = NULL; + goto out2; + } bzero(iterator, sizeof(*iterator)); key = (HotFileKey*) &iterator->key; key->keyLength = HFC_KEYLENGTH; @@ -542,7 +596,7 @@ hfs_recording_init(struct hfsmount *hfsmp, struct proc *p) record.itemSize = sizeof(u_int32_t); record.itemCount = 1; #if HFC_VERBOSE - printf("Evaluating space for \"%s\" metadata zone...\n", HFSTOVCB(hfsmp)->vcbVN); + printf("hfs: Evaluating space for \"%s\" metadata zone...\n", HFSTOVCB(hfsmp)->vcbVN); #endif /* * Get ready to scan the Catalog file. @@ -557,15 +611,14 @@ hfs_recording_init(struct hfsmount *hfsmp, struct proc *p) /* * The writes to Hot File B-tree file are journaled. */ - hfs_global_shared_lock_acquire(hfsmp); - if (hfsmp->jnl) { - if (journal_start_transaction(hfsmp->jnl) != 0) { - hfs_global_shared_lock_release(hfsmp); - error = EINVAL; - goto out1; - } + if (hfs_start_transaction(hfsmp) != 0) { + error = EINVAL; + goto out1; } - vn_lock(hfsmp->hfc_filevp, LK_EXCLUSIVE | LK_RETRY, p); + if (hfs_lock(VTOC(hfsmp->hfc_filevp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT) != 0) { + error = EPERM; + goto out0; + } filefork = VTOF(hfsmp->hfc_filevp); /* @@ -614,7 +667,7 @@ hfs_recording_init(struct hfsmount *hfsmp, struct proc *p) key->fileID = cnid; key->forkType = 0; data = 0x3f3f3f3f; - error = BTInsertRecord(filefork, iterator, &record, sizeof(data)); + error = BTInsertRecord(filefork, iterator, &record, record.itemSize); if (error) { printf("hfs_recording_init: BTInsertRecord failed %d (fileid %d)\n", error, key->fileID); error = MacToVFSError(error); @@ -627,7 +680,7 @@ hfs_recording_init(struct hfsmount *hfsmp, struct proc *p) key->fileID = cnid; key->forkType = 0; data = HFC_MINIMUM_TEMPERATURE; - error = BTInsertRecord(filefork, iterator, &record, sizeof(data)); + error = BTInsertRecord(filefork, iterator, &record, record.itemSize); if (error) { printf("hfs_recording_init: BTInsertRecord failed %d (fileid %d)\n", error, key->fileID); error = MacToVFSError(error); @@ -636,20 +689,20 @@ hfs_recording_init(struct hfsmount *hfsmp, struct proc *p) inserted++; } (void) BTFlushPath(filefork); - (void) VOP_UNLOCK(hfsmp->hfc_filevp, 0, p); + hfs_unlock(VTOC(hfsmp->hfc_filevp)); - if (hfsmp->jnl) { - journal_end_transaction(hfsmp->jnl); - } - hfs_global_shared_lock_release(hfsmp); +out0: + hfs_end_transaction(hfsmp); #if HFC_VERBOSE - printf("%d files identified out of %d\n", inserted, filecount); + printf("hfs: %d files identified out of %d\n", inserted, filecount); #endif out1: (void) BTScanTerminate(&scanstate, &data, &data, &data); out2: - FREE(iterator, M_TEMP); + hfs_end_transaction(hfsmp); + if (iterator) + FREE(iterator, M_TEMP); if (hfsmp->hfc_filevp) { (void) hfc_btree_close(hfsmp, hfsmp->hfc_filevp); hfsmp->hfc_filevp = NULL; @@ -663,29 +716,37 @@ out2: /* * Use sync to perform ocassional background work. */ -__private_extern__ int -hfs_hotfilesync(struct hfsmount *hfsmp, struct proc *p) +hfs_hotfilesync(struct hfsmount *hfsmp, vfs_context_t ctx) { - if ((HFSTOVFS(hfsmp)->mnt_kern_flag & MNTK_UNMOUNT) == 0 && hfsmp->hfc_stage) { + if (hfsmp->hfc_stage) { + struct timeval tv; + + lck_mtx_lock(&hfsmp->hfc_mutex); + switch (hfsmp->hfc_stage) { case HFC_IDLE: - (void) hfs_recording_start(hfsmp, p); + (void) hfs_recording_start(hfsmp); break; case HFC_RECORDING: - if (time.tv_sec > hfsmp->hfc_timeout) - (void) hfs_recording_stop(hfsmp, p); + microtime(&tv); + if (tv.tv_sec > hfsmp->hfc_timeout) + (void) hfs_recording_stop(hfsmp); break; case HFC_EVICTION: - (void) hotfiles_evict(hfsmp, p); + (void) hotfiles_evict(hfsmp, ctx); break; case HFC_ADOPTION: - (void) hotfiles_adopt(hfsmp, p); + (void) hotfiles_adopt(hfsmp); + break; + default: break; } + + lck_mtx_unlock(&hfsmp->hfc_mutex); } return (0); } @@ -699,10 +760,26 @@ hfs_hotfilesync(struct hfsmount *hfsmp, struct proc *p) * NOTE: Since both the data and resource fork can be hot, * there can be two entries for the same file id. * + * Note: the cnode is locked on entry. */ -__private_extern__ int hfs_addhotfile(struct vnode *vp) +{ + hfsmount_t *hfsmp; + int error; + + hfsmp = VTOHFS(vp); + if (hfsmp->hfc_stage != HFC_RECORDING) + return (0); + + lck_mtx_lock(&hfsmp->hfc_mutex); + error = hfs_addhotfile_internal(vp); + lck_mtx_unlock(&hfsmp->hfc_mutex); + return (error); +} + +static int +hfs_addhotfile_internal(struct vnode *vp) { hotfile_data_t *hotdata; hotfile_entry_t *entry; @@ -714,11 +791,18 @@ hfs_addhotfile(struct vnode *vp) hfsmp = VTOHFS(vp); if (hfsmp->hfc_stage != HFC_RECORDING) return (0); - - if (!(vp->v_type == VREG || vp->v_type == VLNK) || - (vp->v_flag & (VSYSTEM | VSWAP))) { + + /* + * Only regular files are eligible for hotfiles addition. + * + * Symlinks were previously added to the list and may exist in + * extant hotfiles regions, but no new ones will be added, and no + * symlinks will now be relocated/evicted from the hotfiles region. + */ + if (!vnode_isreg(vp) || vnode_issystem(vp)) { return (0); } + /* Skip resource forks for now. */ if (VNODE_IS_RSRC(vp)) { return (0); @@ -731,9 +815,10 @@ hfs_addhotfile(struct vnode *vp) if ((ffp->ff_bytesread == 0) || (ffp->ff_blocks == 0) || + (ffp->ff_size == 0) || (ffp->ff_blocks > hotdata->maxblocks) || (cp->c_flag & (C_DELETED | C_NOEXISTS)) || - (cp->c_flags & UF_NODUMP) || + (cp->c_bsdflags & UF_NODUMP) || (cp->c_atime < hfsmp->hfc_timebase)) { return (0); } @@ -763,15 +848,15 @@ hfs_addhotfile(struct vnode *vp) } /* - * Remove a hot file to the recording list. + * Remove a hot file from the recording list. * * This can happen when a hot file becomes * an active vnode (active hot files are * not kept in the recording list until the * end of the recording period). * + * Note: the cnode is locked on entry. */ -__private_extern__ int hfs_removehotfile(struct vnode *vp) { @@ -785,31 +870,35 @@ hfs_removehotfile(struct vnode *vp) if (hfsmp->hfc_stage != HFC_RECORDING) return (0); - if (!(vp->v_type == VREG || vp->v_type == VLNK) || - (vp->v_flag & (VSYSTEM | VSWAP))) { + if ((!vnode_isreg(vp)) || vnode_issystem(vp)) { return (0); } - if ((hotdata = (hotfile_data_t *)hfsmp->hfc_recdata) == NULL) - return (0); ffp = VTOF(vp); cp = VTOC(vp); if ((ffp->ff_bytesread == 0) || (ffp->ff_blocks == 0) || - (cp->c_atime < hfsmp->hfc_timebase)) { + (ffp->ff_size == 0) || (cp->c_atime < hfsmp->hfc_timebase)) { return (0); } + lck_mtx_lock(&hfsmp->hfc_mutex); + if (hfsmp->hfc_stage != HFC_RECORDING) + goto out; + if ((hotdata = (hotfile_data_t *)hfsmp->hfc_recdata) == NULL) + goto out; + temperature = ffp->ff_bytesread / ffp->ff_size; if (temperature < hotdata->threshold) - return (0); + goto out; if (hotdata->coldest && (temperature >= hotdata->coldest->temperature)) { ++hotdata->refcount; hf_delete(hotdata, VTOC(vp)->c_fileid, temperature); --hotdata->refcount; } - +out: + lck_mtx_unlock(&hfsmp->hfc_mutex); return (0); } @@ -820,58 +909,35 @@ hfs_removehotfile(struct vnode *vp) *======================================================================== */ +static int +hotfiles_collect_callback(struct vnode *vp, __unused void *cargs) +{ + if ((vnode_isreg(vp)) && !vnode_issystem(vp)) + (void) hfs_addhotfile_internal(vp); + + return (VNODE_RETURNED); +} + /* * Add all active hot files to the recording list. */ static int -hotfiles_collect(struct hfsmount *hfsmp, struct proc *p) +hotfiles_collect(struct hfsmount *hfsmp) { struct mount *mp = HFSTOVFS(hfsmp); - struct vnode *nvp, *vp; - struct cnode *cp; - int error; - if (vfs_busy(mp, LK_NOWAIT, 0, p)) + if (vfs_busy(mp, LK_NOWAIT)) return (0); -loop: - simple_lock(&mntvnode_slock); - for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { - if (vp->v_mount != mp) { - simple_unlock(&mntvnode_slock); - goto loop; - } - simple_lock(&vp->v_interlock); - nvp = vp->v_mntvnodes.le_next; - if ((vp->v_flag & VSYSTEM) || - !(vp->v_type == VREG || vp->v_type == VLNK)) { - simple_unlock(&vp->v_interlock); - continue; - } - - cp = VTOC(vp); - if (cp == NULL || vp->v_flag & (VXLOCK|VORECLAIM)) { - simple_unlock(&vp->v_interlock); - continue; - } - - simple_unlock(&mntvnode_slock); - error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p); - if (error) { - if (error == ENOENT) - goto loop; - simple_lock(&mntvnode_slock); - continue; - } - (void) hfs_addhotfile(vp); - vput(vp); - - simple_lock(&mntvnode_slock); - } - - simple_unlock(&mntvnode_slock); + /* + * hotfiles_collect_callback will be called for each vnode + * hung off of this mount point + * the vnode will be + * properly referenced and unreferenced around the callback + */ + vnode_iterate(mp, 0, hotfiles_collect_callback, (void *)NULL); - vfs_unbusy(mp, p); + vfs_unbusy(mp); return (0); } @@ -882,7 +948,7 @@ loop: * This is called from within BTUpdateRecord. */ static int -update_callback(const HotFileKey *key, u_int32_t *data, u_int16_t datalen, u_int32_t *state) +update_callback(const HotFileKey *key, u_int32_t *data, u_int32_t *state) { if (key->temperature == HFC_LOOKUPTAG) *data = *state; @@ -893,11 +959,10 @@ update_callback(const HotFileKey *key, u_int32_t *data, u_int16_t datalen, u_int * Identify files already in hot area. */ static int -hotfiles_refine(struct hfsmount *hfsmp, struct proc *p) +hotfiles_refine(struct hfsmount *hfsmp) { - BTreeIterator * iterator; + BTreeIterator * iterator = NULL; struct mount *mp; - struct vnode *vp; filefork_t * filefork; hotfilelist_t *listp; FSBufferDescriptor record; @@ -913,6 +978,10 @@ hotfiles_refine(struct hfsmount *hfsmp, struct proc *p) mp = HFSTOVFS(hfsmp); MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK); + if (iterator == NULL) { + error = ENOMEM; + goto out; + } bzero(iterator, sizeof(*iterator)); key = (HotFileKey*) &iterator->key; @@ -920,15 +989,14 @@ hotfiles_refine(struct hfsmount *hfsmp, struct proc *p) record.itemSize = sizeof(u_int32_t); record.itemCount = 1; - hfs_global_shared_lock_acquire(hfsmp); - if (hfsmp->jnl) { - if (journal_start_transaction(hfsmp->jnl) != 0) { - hfs_global_shared_lock_release(hfsmp); - error = EINVAL; - goto out; - } + if (hfs_start_transaction(hfsmp) != 0) { + error = EINVAL; + goto out; } - vn_lock(hfsmp->hfc_filevp, LK_EXCLUSIVE | LK_RETRY, p); + if (hfs_lock(VTOC(hfsmp->hfc_filevp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT) != 0) { + error = EPERM; + goto out1; + } filefork = VTOF(hfsmp->hfc_filevp); for (i = 0; i < listp->hfl_count; ++i) { @@ -951,7 +1019,7 @@ hotfiles_refine(struct hfsmount *hfsmp, struct proc *p) (IterateCallBackProcPtr)update_callback, &listp->hfl_hotfile[i].hf_temperature); if (error) { - printf("hotfiles_refine: BTUpdateRecord failed %d (file %d)\n", error, key->fileID); + printf("hfs: hotfiles_refine: BTUpdateRecord failed %d (file %d)\n", error, key->fileID); error = MacToVFSError(error); // break; } @@ -967,7 +1035,7 @@ hotfiles_refine(struct hfsmount *hfsmp, struct proc *p) (void) BTSearchRecord(filefork, iterator, &record, NULL, iterator); error = BTDeleteRecord(filefork, iterator); if (error) { - printf("hotfiles_refine: BTDeleteRecord failed %d (file %d)\n", error, key->fileID); + printf("hfs: hotfiles_refine: BTDeleteRecord failed %d (file %d)\n", error, key->fileID); error = MacToVFSError(error); break; } @@ -975,9 +1043,9 @@ hotfiles_refine(struct hfsmount *hfsmp, struct proc *p) key->temperature = listp->hfl_hotfile[i].hf_temperature; key->fileID = listp->hfl_hotfile[i].hf_fileid; key->forkType = 0; - error = BTInsertRecord(filefork, iterator, &record, sizeof(data)); + error = BTInsertRecord(filefork, iterator, &record, record.itemSize); if (error) { - printf("hotfiles_refine: BTInsertRecord failed %d (file %d)\n", error, key->fileID); + printf("hfs: hotfiles_refine: BTInsertRecord failed %d (file %d)\n", error, key->fileID); error = MacToVFSError(error); break; } @@ -991,25 +1059,25 @@ hotfiles_refine(struct hfsmount *hfsmp, struct proc *p) } /* end for */ (void) BTFlushPath(filefork); - (void) VOP_UNLOCK(hfsmp->hfc_filevp, 0, p); + hfs_unlock(VTOC(hfsmp->hfc_filevp)); - if (hfsmp->jnl) { - journal_end_transaction(hfsmp->jnl); - } - hfs_global_shared_lock_release(hfsmp); +out1: + hfs_end_transaction(hfsmp); out: - FREE(iterator, M_TEMP); + if (iterator) + FREE(iterator, M_TEMP); return (error); } /* * Move new hot files into hot area. + * + * Requires that the hfc_mutex be held. */ static int -hotfiles_adopt(struct hfsmount *hfsmp, struct proc *p) +hotfiles_adopt(struct hfsmount *hfsmp) { - BTreeIterator * iterator; - struct mount *mp; + BTreeIterator * iterator = NULL; struct vnode *vp; filefork_t * filefork; hotfilelist_t *listp; @@ -1023,7 +1091,6 @@ hotfiles_adopt(struct hfsmount *hfsmp, struct proc *p) int last; int error = 0; int startedtrans = 0; - int aquiredlock = 0; if ((listp = (hotfilelist_t *)hfsmp->hfc_recdata) == NULL) return (0); @@ -1031,16 +1098,24 @@ hotfiles_adopt(struct hfsmount *hfsmp, struct proc *p) if (hfsmp->hfc_stage != HFC_ADOPTION) { return (EBUSY); } + if (hfs_lock(VTOC(hfsmp->hfc_filevp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT) != 0) { + return (EPERM); + } + + MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK); + if (iterator == NULL) { + hfs_unlock(VTOC(hfsmp->hfc_filevp)); + return (ENOMEM); + } + stage = hfsmp->hfc_stage; hfsmp->hfc_stage = HFC_BUSY; - mp = HFSTOVFS(hfsmp); blksmoved = 0; last = listp->hfl_next + HFC_FILESPERSYNC; if (last > listp->hfl_count) last = listp->hfl_count; - MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK); bzero(iterator, sizeof(*iterator)); key = (HotFileKey*) &iterator->key; key->keyLength = HFC_KEYLENGTH; @@ -1049,7 +1124,6 @@ hotfiles_adopt(struct hfsmount *hfsmp, struct proc *p) record.itemSize = sizeof(u_int32_t); record.itemCount = 1; - vn_lock(hfsmp->hfc_filevp, LK_EXCLUSIVE | LK_RETRY, p); filefork = VTOF(hfsmp->hfc_filevp); for (i = listp->hfl_next; (i < last) && (blksmoved < HFC_BLKSPERSYNC); ++i) { @@ -1063,7 +1137,7 @@ hotfiles_adopt(struct hfsmount *hfsmp, struct proc *p) /* * Acquire a vnode for this file. */ - error = VFS_VGET(mp, &listp->hfl_hotfile[i].hf_fileid, &vp); + error = hfs_vget(hfsmp, listp->hfl_hotfile[i].hf_fileid, &vp, 0, 0); if (error) { if (error == ENOENT) { error = 0; @@ -1072,23 +1146,27 @@ hotfiles_adopt(struct hfsmount *hfsmp, struct proc *p) } break; } - if (vp->v_type != VREG && vp->v_type != VLNK) { - printf("hotfiles_adopt: huh, not a file %d (%d)\n", listp->hfl_hotfile[i].hf_fileid, VTOC(vp)->c_cnid); - vput(vp); - listp->hfl_hotfile[i].hf_temperature == 0; + if (!vnode_isreg(vp)) { + /* Symlinks are ineligible for adoption into the hotfile zone. */ + printf("hfs: hotfiles_adopt: huh, not a file %d (%d)\n", listp->hfl_hotfile[i].hf_fileid, VTOC(vp)->c_cnid); + hfs_unlock(VTOC(vp)); + vnode_put(vp); + listp->hfl_hotfile[i].hf_temperature = 0; listp->hfl_next++; continue; /* stale entry, go to next */ } if (hotextents(hfsmp, &VTOF(vp)->ff_extents[0])) { - vput(vp); - listp->hfl_hotfile[i].hf_temperature == 0; + hfs_unlock(VTOC(vp)); + vnode_put(vp); + listp->hfl_hotfile[i].hf_temperature = 0; listp->hfl_next++; listp->hfl_totalblocks -= listp->hfl_hotfile[i].hf_blocks; continue; /* stale entry, go to next */ } fileblocks = VTOF(vp)->ff_blocks; if (fileblocks > hfsmp->hfs_hotfile_freeblks) { - vput(vp); + hfs_unlock(VTOC(vp)); + vnode_put(vp); listp->hfl_next++; listp->hfl_totalblocks -= fileblocks; continue; /* entry too big, go to next */ @@ -1096,26 +1174,23 @@ hotfiles_adopt(struct hfsmount *hfsmp, struct proc *p) if ((blksmoved > 0) && (blksmoved + fileblocks) > HFC_BLKSPERSYNC) { - vput(vp); - break; + hfs_unlock(VTOC(vp)); + vnode_put(vp); + break; /* adopt this entry the next time around */ } - /* Start a new transaction. */ - hfs_global_shared_lock_acquire(hfsmp); - aquiredlock = 1; - if (hfsmp->jnl) { - if (journal_start_transaction(hfsmp->jnl) != 0) { - error = EINVAL; - vput(vp); - break; - } - startedtrans = 1; - } + if (VTOC(vp)->c_desc.cd_nameptr) + data = *(const u_int32_t *)(VTOC(vp)->c_desc.cd_nameptr); + else + data = 0x3f3f3f3f; - error = hfs_relocate(vp, hfsmp->hfs_hotfile_start, p->p_ucred, p); - vput(vp); - if (error) - break; - + error = hfs_relocate(vp, hfsmp->hfs_hotfile_start, kauth_cred_get(), current_proc()); + hfs_unlock(VTOC(vp)); + vnode_put(vp); + if (error) { + /* Move on to next item. */ + listp->hfl_next++; + continue; + } /* Keep hot file free space current. */ hfsmp->hfs_hotfile_freeblks -= fileblocks; listp->hfl_totalblocks -= fileblocks; @@ -1125,14 +1200,17 @@ hotfiles_adopt(struct hfsmount *hfsmp, struct proc *p) key->temperature = listp->hfl_hotfile[i].hf_temperature; key->fileID = listp->hfl_hotfile[i].hf_fileid; key->forkType = 0; - if (VTOC(vp)->c_desc.cd_nameptr) - data = *(u_int32_t *)(VTOC(vp)->c_desc.cd_nameptr); - else - data = 0x3f3f3f3f; - error = BTInsertRecord(filefork, iterator, &record, sizeof(data)); + /* Start a new transaction before calling BTree code. */ + if (hfs_start_transaction(hfsmp) != 0) { + error = EINVAL; + break; + } + startedtrans = 1; + + error = BTInsertRecord(filefork, iterator, &record, record.itemSize); if (error) { - printf("hotfiles_adopt: BTInsertRecord failed %d (fileid %d)\n", error, key->fileID); + printf("hfs: hotfiles_adopt: BTInsertRecord failed %d (fileid %d)\n", error, key->fileID); error = MacToVFSError(error); stage = HFC_IDLE; break; @@ -1144,9 +1222,9 @@ hotfiles_adopt(struct hfsmount *hfsmp, struct proc *p) key->fileID = listp->hfl_hotfile[i].hf_fileid; key->forkType = 0; data = listp->hfl_hotfile[i].hf_temperature; - error = BTInsertRecord(filefork, iterator, &record, sizeof(data)); + error = BTInsertRecord(filefork, iterator, &record, record.itemSize); if (error) { - printf("hotfiles_adopt: BTInsertRecord failed %d (fileid %d)\n", error, key->fileID); + printf("hfs: hotfiles_adopt: BTInsertRecord failed %d (fileid %d)\n", error, key->fileID); error = MacToVFSError(error); stage = HFC_IDLE; break; @@ -1155,11 +1233,9 @@ hotfiles_adopt(struct hfsmount *hfsmp, struct proc *p) /* Transaction complete. */ if (startedtrans) { - journal_end_transaction(hfsmp->jnl); - startedtrans = 0; + hfs_end_transaction(hfsmp); + startedtrans = 0; } - hfs_global_shared_lock_release(hfsmp); - aquiredlock = 0; blksmoved += fileblocks; listp->hfl_next++; @@ -1168,31 +1244,27 @@ hotfiles_adopt(struct hfsmount *hfsmp, struct proc *p) } if (hfsmp->hfs_hotfile_freeblks <= 0) { #if HFC_VERBOSE - printf("hotfiles_adopt: free space exhausted (%d)\n", hfsmp->hfs_hotfile_freeblks); + printf("hfs: hotfiles_adopt: free space exhausted (%d)\n", hfsmp->hfs_hotfile_freeblks); #endif break; } } /* end for */ #if HFC_VERBOSE - printf("hotfiles_adopt: [%d] adopted %d blocks (%d left)\n", listp->hfl_next, blksmoved, listp->hfl_totalblocks); + printf("hfs: hotfiles_adopt: [%d] adopted %d blocks (%d left)\n", listp->hfl_next, blksmoved, listp->hfl_totalblocks); #endif /* Finish any outstanding transactions. */ if (startedtrans) { (void) BTFlushPath(filefork); - journal_end_transaction(hfsmp->jnl); + hfs_end_transaction(hfsmp); startedtrans = 0; } - if (aquiredlock) { - hfs_global_shared_lock_release(hfsmp); - aquiredlock = 0; - } - (void) VOP_UNLOCK(hfsmp->hfc_filevp, 0, p); + hfs_unlock(VTOC(hfsmp->hfc_filevp)); if ((listp->hfl_next >= listp->hfl_count) || (hfsmp->hfs_hotfile_freeblks <= 0)) { #if HFC_VERBOSE - printf("hotfiles_adopt: all done relocating %d files\n", listp->hfl_count); - printf("hotfiles_adopt: %d blocks free in hot file band\n", hfsmp->hfs_hotfile_freeblks); + printf("hfs: hotfiles_adopt: all done relocating %d files\n", listp->hfl_count); + printf("hfs: hotfiles_adopt: %d blocks free in hot file band\n", hfsmp->hfs_hotfile_freeblks); #endif stage = HFC_IDLE; } @@ -1209,23 +1281,25 @@ hotfiles_adopt(struct hfsmount *hfsmp, struct proc *p) /* * Reclaim space by evicting the coldest files. + * + * Requires that the hfc_mutex be held. */ static int -hotfiles_evict(struct hfsmount *hfsmp, struct proc *p) +hotfiles_evict(struct hfsmount *hfsmp, vfs_context_t ctx) { - BTreeIterator * iterator; - struct mount *mp; + BTreeIterator * iterator = NULL; struct vnode *vp; HotFileKey * key; filefork_t * filefork; hotfilelist_t *listp; enum hfc_stage stage; + u_int32_t savedtemp; int blksmoved; int filesmoved; int fileblocks; int error = 0; int startedtrans = 0; - int aquiredlock = 0; + int bt_op; if (hfsmp->hfc_stage != HFC_EVICTION) { return (EBUSY); @@ -1234,17 +1308,25 @@ hotfiles_evict(struct hfsmount *hfsmp, struct proc *p) if ((listp = (hotfilelist_t *)hfsmp->hfc_recdata) == NULL) return (0); + if (hfs_lock(VTOC(hfsmp->hfc_filevp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT) != 0) { + return (EPERM); + } + + MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK); + if (iterator == NULL) { + hfs_unlock(VTOC(hfsmp->hfc_filevp)); + return (ENOMEM); + } + stage = hfsmp->hfc_stage; hfsmp->hfc_stage = HFC_BUSY; - mp = HFSTOVFS(hfsmp); filesmoved = blksmoved = 0; + bt_op = kBTreeFirstRecord; - MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK); bzero(iterator, sizeof(*iterator)); key = (HotFileKey*) &iterator->key; - vn_lock(hfsmp->hfc_filevp, LK_EXCLUSIVE | LK_RETRY, p); filefork = VTOF(hfsmp->hfc_filevp); while (listp->hfl_reclaimblks > 0 && @@ -1254,22 +1336,22 @@ hotfiles_evict(struct hfsmount *hfsmp, struct proc *p) /* * Obtain the first record (ie the coldest one). */ - if (BTIterateRecord(filefork, kBTreeFirstRecord, iterator, NULL, NULL) != 0) { + if (BTIterateRecord(filefork, bt_op, iterator, NULL, NULL) != 0) { #if HFC_VERBOSE - printf("hotfiles_evict: no more records\n"); + printf("hfs: hotfiles_evict: no more records\n"); #endif error = 0; stage = HFC_ADOPTION; break; } if (key->keyLength != HFC_KEYLENGTH) { - printf("hotfiles_evict: invalid key length %d\n", key->keyLength); + printf("hfs: hotfiles_evict: invalid key length %d\n", key->keyLength); error = EFTYPE; break; } if (key->temperature == HFC_LOOKUPTAG) { #if HFC_VERBOSE - printf("hotfiles_evict: ran into thread records\n"); + printf("hfs: hotfiles_evict: ran into thread records\n"); #endif error = 0; stage = HFC_ADOPTION; @@ -1278,44 +1360,33 @@ hotfiles_evict(struct hfsmount *hfsmp, struct proc *p) /* * Aquire the vnode for this file. */ - error = VFS_VGET(mp, &key->fileID, &vp); - - /* Start a new transaction. */ - hfs_global_shared_lock_acquire(hfsmp); - aquiredlock = 1; - if (hfsmp->jnl) { - if (journal_start_transaction(hfsmp->jnl) != 0) { - if (error == 0) - vput(vp); - error = EINVAL; - break; - } - startedtrans = 1; - } + error = hfs_vget(hfsmp, key->fileID, &vp, 0, 0); if (error) { if (error == ENOENT) { - (void) BTDeleteRecord(filefork, iterator); - key->temperature = HFC_LOOKUPTAG; - (void) BTDeleteRecord(filefork, iterator); - goto next; /* stale entry, go to next */ + goto delete; /* stale entry, go to next */ } else { - printf("hotfiles_evict: err %d getting file %d (%d)\n", + printf("hfs: hotfiles_evict: err %d getting file %d\n", error, key->fileID); } break; } - if (vp->v_type != VREG && vp->v_type != VLNK) { - printf("hotfiles_evict: huh, not a file %d\n", key->fileID); - vput(vp); - (void) BTDeleteRecord(filefork, iterator); - key->temperature = HFC_LOOKUPTAG; - (void) BTDeleteRecord(filefork, iterator); - goto next; /* invalid entry, go to next */ + + /* + * Symlinks that may have been inserted into the hotfile zone during a previous OS are now stuck + * here. We do not want to move them. + */ + if (!vnode_isreg(vp)) { + printf("hfs: hotfiles_evict: huh, not a file %d\n", key->fileID); + hfs_unlock(VTOC(vp)); + vnode_put(vp); + goto delete; /* invalid entry, go to next */ } + fileblocks = VTOF(vp)->ff_blocks; if ((blksmoved > 0) && (blksmoved + fileblocks) > HFC_BLKSPERSYNC) { - vput(vp); + hfs_unlock(VTOC(vp)); + vnode_put(vp); break; } /* @@ -1323,28 +1394,34 @@ hotfiles_evict(struct hfsmount *hfsmp, struct proc *p) */ if (!hotextents(hfsmp, &VTOF(vp)->ff_extents[0])) { #if HFC_VERBOSE - printf("hotfiles_evict: file %d isn't hot!\n", key->fileID); + printf("hfs: hotfiles_evict: file %d isn't hot!\n", key->fileID); #endif - vput(vp); - (void) BTDeleteRecord(filefork, iterator); - key->temperature = HFC_LOOKUPTAG; - (void) BTDeleteRecord(filefork, iterator); - goto next; /* go to next */ + hfs_unlock(VTOC(vp)); + vnode_put(vp); + goto delete; /* stale entry, go to next */ } /* * Relocate file out of hot area. */ - error = hfs_relocate(vp, HFSTOVCB(hfsmp)->nextAllocation, p->p_ucred, p); + error = hfs_relocate(vp, HFSTOVCB(hfsmp)->nextAllocation, vfs_context_ucred(ctx), vfs_context_proc(ctx)); if (error) { - /* XXX skip to next record here! */ - printf("hotfiles_evict: err % relocating file\n", error, key->fileID); - vput(vp); - break; + printf("hfs: hotfiles_evict: err %d relocating file %d\n", error, key->fileID); + hfs_unlock(VTOC(vp)); + vnode_put(vp); + bt_op = kBTreeNextRecord; + goto next; /* go to next */ } - (void) VOP_FSYNC(vp, p->p_ucred, MNT_WAIT, p); - vput(vp); + // + // We do not believe that this call to hfs_fsync() is + // necessary and it causes a journal transaction + // deadlock so we are removing it. + // + // (void) hfs_fsync(vp, MNT_WAIT, 0, p); + + hfs_unlock(VTOC(vp)); + vnode_put(vp); hfsmp->hfs_hotfile_freeblks += fileblocks; listp->hfl_reclaimblks -= fileblocks; @@ -1352,47 +1429,48 @@ hotfiles_evict(struct hfsmount *hfsmp, struct proc *p) listp->hfl_reclaimblks = 0; blksmoved += fileblocks; filesmoved++; +delete: + /* Start a new transaction before calling BTree code. */ + if (hfs_start_transaction(hfsmp) != 0) { + error = EINVAL; + break; + } + startedtrans = 1; error = BTDeleteRecord(filefork, iterator); if (error) { - printf("hotfiles_evict: BTDeleteRecord failed %d (fileid %d)\n", error, key->fileID); error = MacToVFSError(error); break; } + savedtemp = key->temperature; key->temperature = HFC_LOOKUPTAG; error = BTDeleteRecord(filefork, iterator); if (error) { - printf("hotfiles_evict: BTDeleteRecord thread failed %d (fileid %d)\n", error, key->fileID); error = MacToVFSError(error); break; } + key->temperature = savedtemp; next: (void) BTFlushPath(filefork); /* Transaction complete. */ if (startedtrans) { - journal_end_transaction(hfsmp->jnl); + hfs_end_transaction(hfsmp); startedtrans = 0; } - hfs_global_shared_lock_release(hfsmp); - aquiredlock = 0; } /* end while */ #if HFC_VERBOSE - printf("hotfiles_evict: moved %d files (%d blks, %d to go)\n", filesmoved, blksmoved, listp->hfl_reclaimblks); + printf("hfs: hotfiles_evict: moved %d files (%d blks, %d to go)\n", filesmoved, blksmoved, listp->hfl_reclaimblks); #endif /* Finish any outstanding transactions. */ if (startedtrans) { (void) BTFlushPath(filefork); - journal_end_transaction(hfsmp->jnl); + hfs_end_transaction(hfsmp); startedtrans = 0; } - if (aquiredlock) { - hfs_global_shared_lock_release(hfsmp); - aquiredlock = 0; - } - (void) VOP_UNLOCK(hfsmp->hfc_filevp, 0, p); + hfs_unlock(VTOC(hfsmp->hfc_filevp)); /* * Move to next stage when finished. @@ -1400,7 +1478,7 @@ next: if (listp->hfl_reclaimblks <= 0) { stage = HFC_ADOPTION; #if HFC_VERBOSE - printf("hotfiles_evict: %d blocks free in hot file band\n", hfsmp->hfs_hotfile_freeblks); + printf("hfs: hotfiles_evict: %d blocks free in hot file band\n", hfsmp->hfs_hotfile_freeblks); #endif } FREE(iterator, M_TEMP); @@ -1413,10 +1491,10 @@ next: * Age the existing records in the hot files b-tree. */ static int -hotfiles_age(struct hfsmount *hfsmp, struct proc *p) +hotfiles_age(struct hfsmount *hfsmp) { BTreeInfoRec btinfo; - BTreeIterator * iterator; + BTreeIterator * iterator = NULL; BTreeIterator * prev_iterator; FSBufferDescriptor record; FSBufferDescriptor prev_record; @@ -1434,6 +1512,10 @@ hotfiles_age(struct hfsmount *hfsmp, struct proc *p) MALLOC(iterator, BTreeIterator *, 2 * sizeof(*iterator), M_TEMP, M_WAITOK); + if (iterator == NULL) { + error = ENOMEM; + goto out2; + } bzero(iterator, 2 * sizeof(*iterator)); key = (HotFileKey*) &iterator->key; @@ -1450,15 +1532,14 @@ hotfiles_age(struct hfsmount *hfsmp, struct proc *p) /* * Capture b-tree changes inside a transaction */ - hfs_global_shared_lock_acquire(hfsmp); - if (hfsmp->jnl) { - if (journal_start_transaction(hfsmp->jnl) != 0) { - hfs_global_shared_lock_release(hfsmp); - error = EINVAL; - goto out2; - } + if (hfs_start_transaction(hfsmp) != 0) { + error = EINVAL; + goto out2; } - vn_lock(hfsmp->hfc_filevp, LK_EXCLUSIVE | LK_RETRY, p); + if (hfs_lock(VTOC(hfsmp->hfc_filevp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT) != 0) { + error = EPERM; + goto out1; + } filefork = VTOF(hfsmp->hfc_filevp); error = BTGetInformation(filefork, 0, &btinfo); @@ -1527,7 +1608,7 @@ hotfiles_age(struct hfsmount *hfsmp, struct proc *p) newtemp = MAX(prev_key->temperature >> 1, 4); prev_key->temperature = newtemp; - error = BTInsertRecord(filefork, prev_iterator, &prev_record, sizeof(data)); + error = BTInsertRecord(filefork, prev_iterator, &prev_record, prev_record.itemSize); if (error) { printf("hfs_agehotfiles: BTInsertRecord failed %d (file %d)\n", error, prev_key->fileID); error = MacToVFSError(error); @@ -1559,15 +1640,12 @@ hotfiles_age(struct hfsmount *hfsmp, struct proc *p) #endif (void) BTFlushPath(filefork); out: - (void) VOP_UNLOCK(hfsmp->hfc_filevp, 0, p); - - if (hfsmp->jnl) { - // hfs_flushvolumeheader(hfsmp, MNT_NOWAIT, 0); - journal_end_transaction(hfsmp->jnl); - } - hfs_global_shared_lock_release(hfsmp); + hfs_unlock(VTOC(hfsmp->hfc_filevp)); +out1: + hfs_end_transaction(hfsmp); out2: - FREE(iterator, M_TEMP); + if (iterator) + FREE(iterator, M_TEMP); return (error); } @@ -1608,55 +1686,56 @@ hotextents(struct hfsmount *hfsmp, HFSPlusExtentDescriptor * extents) /* * Open the hot files b-tree for writing. * - * On successful exit the vnode has a reference but is unlocked. + * On successful exit the vnode has a reference but not an iocount. */ static int hfc_btree_open(struct hfsmount *hfsmp, struct vnode **vpp) { - struct proc *p; + proc_t p; struct vnode *vp; - struct cat_desc cdesc = {0}; + struct cat_desc cdesc; struct cat_attr cattr; struct cat_fork cfork; static char filename[] = HFC_FILENAME; int error; int retry = 0; + int lockflags; + int newvnode_flags = 0; *vpp = NULL; p = current_proc(); + bzero(&cdesc, sizeof(cdesc)); cdesc.cd_parentcnid = kRootDirID; - cdesc.cd_nameptr = filename; + cdesc.cd_nameptr = (const u_int8_t *)filename; cdesc.cd_namelen = strlen(filename); - /* Lock catalog b-tree */ - error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_SHARED, p); - if (error) - return (error); + lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK); - error = cat_lookup(hfsmp, &cdesc, 0, &cdesc, &cattr, &cfork); + error = cat_lookup(hfsmp, &cdesc, 0, 0, &cdesc, &cattr, &cfork, NULL); - /* Unlock catalog b-tree */ - (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); + hfs_systemfile_unlock(hfsmp, lockflags); if (error) { - printf("hfc_btree_open: cat_lookup error %d\n", error); + printf("hfs: hfc_btree_open: cat_lookup error %d\n", error); return (error); } again: cdesc.cd_flags |= CD_ISMETA; - error = hfs_getnewvnode(hfsmp, NULL, &cdesc, 0, &cattr, &cfork, &vp); + error = hfs_getnewvnode(hfsmp, NULL, NULL, &cdesc, 0, &cattr, + &cfork, &vp, &newvnode_flags); if (error) { - printf("hfc_btree_open: hfs_getnewvnode error %d\n", error); + printf("hfs: hfc_btree_open: hfs_getnewvnode error %d\n", error); cat_releasedesc(&cdesc); return (error); } - if ((vp->v_flag & VSYSTEM) == 0) { + if (!vnode_issystem(vp)) { #if HFC_VERBOSE - printf("hfc_btree_open: file has UBC, try again\n"); + printf("hfs: hfc_btree_open: file has UBC, try again\n"); #endif - vput(vp); - vgone(vp); + hfs_unlock(VTOC(vp)); + vnode_recycle(vp); + vnode_put(vp); if (retry++ == 0) goto again; else @@ -1666,34 +1745,19 @@ again: /* Open the B-tree file for writing... */ error = BTOpenPath(VTOF(vp), (KeyCompareProcPtr) hfc_comparekeys); if (error) { - printf("hfc_btree_open: BTOpenPath error %d\n", error); + printf("hfs: hfc_btree_open: BTOpenPath error %d\n", error); error = MacToVFSError(error); - } else { -#if HFC_VERBOSE - struct BTreeInfoRec btinfo; - - if (BTGetInformation(VTOF(vp), 0, &btinfo) == 0) { - printf("btinfo: nodeSize %d\n", btinfo.nodeSize); - printf("btinfo: maxKeyLength %d\n", btinfo.maxKeyLength); - printf("btinfo: treeDepth %d\n", btinfo.treeDepth); - printf("btinfo: numRecords %d\n", btinfo.numRecords); - printf("btinfo: numNodes %d\n", btinfo.numNodes); - printf("btinfo: numFreeNodes %d\n", btinfo.numFreeNodes); - } -#endif } - VOP_UNLOCK(vp, 0, p); /* unlocked with a single reference */ - if (error) - vrele(vp); - else + hfs_unlock(VTOC(vp)); + if (error == 0) { *vpp = vp; + vnode_ref(vp); /* keep a reference while its open */ + } + vnode_put(vp); - if ((vp->v_flag & VSYSTEM) == 0) - panic("hfc_btree_open: not a system file (vp = 0x%08x)", vp); - - if (UBCINFOEXISTS(vp)) - panic("hfc_btree_open: has UBCInfo (vp = 0x%08x)", vp); + if (!vnode_issystem(vp)) + panic("hfs: hfc_btree_open: not a system file (vp = %p)", vp); return (error); } @@ -1701,31 +1765,32 @@ again: /* * Close the hot files b-tree. * - * On entry the vnode is not locked but has a reference. + * On entry the vnode has a reference. */ static int hfc_btree_close(struct hfsmount *hfsmp, struct vnode *vp) { - struct proc *p = current_proc(); - int error; + proc_t p = current_proc(); + int error = 0; if (hfsmp->jnl) { - journal_flush(hfsmp->jnl); + hfs_journal_flush(hfsmp, FALSE); } - if (vget(vp, LK_EXCLUSIVE, p) == 0) { - (void) VOP_FSYNC(vp, NOCRED, MNT_WAIT, p); - error = BTClosePath(VTOF(vp)); - if (error) - printf("hfc_btree_close: BTClosePath error %d\n", error); - vput(vp); + if (vnode_get(vp) == 0) { + error = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT); + if (error == 0) { + (void) hfs_fsync(vp, MNT_WAIT, 0, p); + error = BTClosePath(VTOF(vp)); + hfs_unlock(VTOC(vp)); + } + vnode_rele(vp); + vnode_recycle(vp); + vnode_put(vp); } - vrele(vp); - vgone(vp); - vp = NULL; - return (0); + return (error); } /* @@ -1733,34 +1798,67 @@ hfc_btree_close(struct hfsmount *hfsmp, struct vnode *vp) * */ static int -hfc_btree_create(struct hfsmount *hfsmp, int nodesize, int entries) +hfc_btree_create(struct hfsmount *hfsmp, unsigned int nodesize, unsigned int entries) { - struct proc *p; - struct nameidata nd; - struct vnode *vp; - char path[128]; + struct vnode *dvp = NULL; + struct vnode *vp = NULL; + struct cnode *cp = NULL; + vfs_context_t ctx = vfs_context_current(); + struct vnode_attr va; + struct componentname cname; + static char filename[] = HFC_FILENAME; int error; - if (hfsmp->hfc_filevp) - panic("hfc_btree_create: hfc_filevp exists (vp = 0x%08x)", hfsmp->hfc_filevp); + panic("hfs: hfc_btree_create: hfc_filevp exists (vp = %p)", hfsmp->hfc_filevp); - p = current_proc(); - snprintf(path, sizeof(path), "%s/%s", - hfsmp->hfs_mp->mnt_stat.f_mntonname, HFC_FILENAME); - NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path, p); - if ((error = vn_open(&nd, O_CREAT | FWRITE, S_IRUSR | S_IWUSR)) != 0) { + error = VFS_ROOT(HFSTOVFS(hfsmp), &dvp, ctx); + if (error) { return (error); } - vp = nd.ni_vp; - + cname.cn_nameiop = CREATE; + cname.cn_flags = ISLASTCN; + cname.cn_context = ctx; + cname.cn_pnbuf = filename; + cname.cn_pnlen = sizeof(filename); + cname.cn_nameptr = filename; + cname.cn_namelen = strlen(filename); + cname.cn_hash = 0; + cname.cn_consume = 0; + + VATTR_INIT(&va); + VATTR_SET(&va, va_type, VREG); + VATTR_SET(&va, va_mode, S_IFREG | S_IRUSR | S_IWUSR); + VATTR_SET(&va, va_uid, 0); + VATTR_SET(&va, va_gid, 0); + + if (hfs_start_transaction(hfsmp) != 0) { + error = EINVAL; + goto out; + } + + /* call ourselves directly, ignore the higher-level VFS file creation code */ + error = VNOP_CREATE(dvp, &vp, &cname, &va, ctx); + if (error) { + printf("hfs: error %d creating HFBT on %s\n", error, HFSTOVCB(hfsmp)->vcbVN); + goto out; + } + if (dvp) { + vnode_put(dvp); + dvp = NULL; + } + if ((error = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT))) { + goto out; + } + cp = VTOC(vp); + /* Don't use non-regular files or files with links. */ - if (vp->v_type != VREG || VTOC(vp)->c_nlink != 1) { + if (!vnode_isreg(vp) || cp->c_linkcount != 1) { error = EFTYPE; goto out; } - printf("HFS: created HFBT on %s\n", HFSTOVCB(hfsmp)->vcbVN); + printf("hfs: created HFBT on %s\n", HFSTOVCB(hfsmp)->vcbVN); if (VTOF(vp)->ff_size < nodesize) { caddr_t buffer; @@ -1776,7 +1874,7 @@ hfc_btree_create(struct hfsmount *hfsmp, int nodesize, int entries) /* * Mark it invisible (truncate will pull these changes). */ - ((FndrFileInfo *)&VTOC(vp)->c_finderinfo[0])->fdFlags |= + ((FndrFileInfo *)&cp->c_finderinfo[0])->fdFlags |= SWAP_BE16 (kIsInvisible + kNameLocked); if (kmem_alloc(kernel_map, (vm_offset_t *)&buffer, nodesize)) { @@ -1784,7 +1882,7 @@ hfc_btree_create(struct hfsmount *hfsmp, int nodesize, int entries) goto out; } bzero(buffer, nodesize); - index = (int16_t *)buffer; + index = (u_int16_t *)buffer; entirespernode = (nodesize - sizeof(BTNodeDescriptor) - 2) / (sizeof(HotFileKey) + 6); @@ -1800,7 +1898,7 @@ hfc_btree_create(struct hfsmount *hfsmp, int nodesize, int entries) index[(nodesize / 2) - 1] = SWAP_BE16 (offset); /* FILL IN THE HEADER RECORD: */ - bthp = (BTHeaderRec *)((UInt8 *)buffer + offset); + bthp = (BTHeaderRec *)((u_int8_t *)buffer + offset); bthp->nodeSize = SWAP_BE16 (nodesize); bthp->totalNodes = SWAP_BE32 (filesize / nodesize); bthp->freeNodes = SWAP_BE32 (nodecnt - 1); @@ -1812,7 +1910,7 @@ hfc_btree_create(struct hfsmount *hfsmp, int nodesize, int entries) index[(nodesize / 2) - 2] = SWAP_BE16 (offset); /* FILL IN THE USER RECORD: */ - hotfileinfo = (HotFilesInfo *)((UInt8 *)buffer + offset); + hotfileinfo = (HotFilesInfo *)((u_int8_t *)buffer + offset); hotfileinfo->magic = SWAP_BE32 (HFC_MAGIC); hotfileinfo->version = SWAP_BE32 (HFC_VERSION); hotfileinfo->duration = SWAP_BE32 (HFC_DEFAULT_DURATION); @@ -1821,7 +1919,8 @@ hfc_btree_create(struct hfsmount *hfsmp, int nodesize, int entries) hotfileinfo->threshold = SWAP_BE32 (HFC_MINIMUM_TEMPERATURE); hotfileinfo->maxfileblks = SWAP_BE32 (HFC_MAXIMUM_FILESIZE / HFSTOVCB(hfsmp)->blockSize); hotfileinfo->maxfilecnt = SWAP_BE32 (HFC_DEFAULT_FILE_COUNT); - strcpy(hotfileinfo->tag, hfc_tag); + strlcpy((char *)hotfileinfo->tag, hfc_tag, + sizeof hotfileinfo->tag); offset += kBTreeHeaderUserBytes; index[(nodesize / 2) - 3] = SWAP_BE16 (offset); @@ -1831,29 +1930,50 @@ hfc_btree_create(struct hfsmount *hfsmp, int nodesize, int entries) - kBTreeHeaderUserBytes - (4 * sizeof(int16_t)); index[(nodesize / 2) - 4] = SWAP_BE16 (offset); - vp->v_flag |= VNOFLUSH; - error = VOP_TRUNCATE(vp, (off_t)filesize, IO_NDELAY, NOCRED, p); + vnode_setnoflush(vp); + error = hfs_truncate(vp, (off_t)filesize, IO_NDELAY, 0, ctx); + if (error) { + printf("hfs: error %d growing HFBT on %s\n", error, HFSTOVCB(hfsmp)->vcbVN); + goto out; + } + cp->c_flag |= C_ZFWANTSYNC; + cp->c_zftimeout = 1; + if (error == 0) { - struct iovec aiov; - struct uio auio; - - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - aiov.iov_base = buffer; - aiov.iov_len = filesize; - auio.uio_resid = nodesize; - auio.uio_offset = (off_t)(0); - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_rw = UIO_WRITE; - auio.uio_procp = (struct proc *)0; - error = VOP_WRITE(vp, &auio, 0, kernproc->p_ucred); + struct vnop_write_args args; + uio_t auio; + + auio = uio_create(1, 0, UIO_SYSSPACE, UIO_WRITE); + uio_addiov(auio, (uintptr_t)buffer, nodesize); + + args.a_desc = &vnop_write_desc; + args.a_vp = vp; + args.a_uio = auio; + args.a_ioflag = 0; + args.a_context = ctx; + + hfs_unlock(cp); + cp = NULL; + + error = hfs_vnop_write(&args); + if (error) + printf("hfs: error %d writing HFBT on %s\n", error, HFSTOVCB(hfsmp)->vcbVN); + + uio_free(auio); } kmem_free(kernel_map, (vm_offset_t)buffer, nodesize); } out: - (void) VOP_UNLOCK(vp, 0, p); - (void) vn_close(vp, FWRITE, kernproc->p_ucred, p); - vgone(vp); + hfs_end_transaction(hfsmp); + if (dvp) { + vnode_put(dvp); + } + if (vp) { + if (cp) + hfs_unlock(cp); + vnode_recycle(vp); + vnode_put(vp); + } return (error); } @@ -1903,6 +2023,7 @@ hfc_comparekeys(HotFileKey *searchKey, HotFileKey *trialKey) /* * Lookup a hot file entry in the tree. */ +#if HFC_DEBUG static hotfile_entry_t * hf_lookup(hotfile_data_t *hotdata, u_int32_t fileid, u_int32_t temperature) { @@ -1923,6 +2044,7 @@ hf_lookup(hotfile_data_t *hotdata, u_int32_t fileid, u_int32_t temperature) } return (entry); } +#endif /* * Insert a hot file entry into the tree. @@ -1993,6 +2115,21 @@ hf_coldest(hotfile_data_t *hotdata) return (entry); } +/* + * Find the hottest entry in the tree. + */ +static hotfile_entry_t * +hf_hottest(hotfile_data_t *hotdata) +{ + hotfile_entry_t *entry = hotdata->rootentry; + + if (entry) { + while (entry->right) + entry = entry->right; + } + return (entry); +} + /* * Delete a hot file entry from the tree. */ @@ -2093,38 +2230,32 @@ hf_getnewentry(hotfile_data_t *hotdata) /* - * Visit the tree in desending order. + * Generate a sorted list of hot files (hottest to coldest). + * + * As a side effect, every node in the hot file tree will be + * deleted (moved to the free list). */ static void -hf_sortlist(hotfile_entry_t * root, int *index, hotfilelist_t *sortedlist) -{ - if (root) { - int i; - - hf_sortlist(root->right, index, sortedlist); - i = *index; - ++(*index); - sortedlist->hfl_hotfile[i].hf_fileid = root->fileid; - sortedlist->hfl_hotfile[i].hf_temperature = root->temperature; - sortedlist->hfl_hotfile[i].hf_blocks = root->blocks; - sortedlist->hfl_totalblocks += root->blocks; - hf_sortlist(root->left, index, sortedlist); - } -} - -/* - * Generate a sorted list of hot files. - */ -static int hf_getsortedlist(hotfile_data_t * hotdata, hotfilelist_t *sortedlist) { - int index = 0; - - hf_sortlist(hotdata->rootentry, &index, sortedlist); + int i = 0; + hotfile_entry_t *entry; + + while ((entry = hf_hottest(hotdata)) != NULL) { + sortedlist->hfl_hotfile[i].hf_fileid = entry->fileid; + sortedlist->hfl_hotfile[i].hf_temperature = entry->temperature; + sortedlist->hfl_hotfile[i].hf_blocks = entry->blocks; + sortedlist->hfl_totalblocks += entry->blocks; + ++i; - sortedlist->hfl_count = hotdata->activefiles; + hf_delete(hotdata, entry->fileid, entry->temperature); + } + + sortedlist->hfl_count = i; - return (index); +#if HFC_VERBOSE + printf("hfs: hf_getsortedlist returned %d entries\n", i); +#endif } @@ -2146,7 +2277,7 @@ hf_printtree(hotfile_entry_t * root) { if (root) { hf_printtree(root->left); - printf("temperature: % 8d, fileid %d\n", root->temperature, root->fileid); + printf("hfs: temperature: % 8d, fileid %d\n", root->temperature, root->fileid); hf_printtree(root->right); } }