X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/8f6c56a50524aa785f7e596d52dddfb331e18961..c18c124eaa464aaaa5549e99e5a70fc9cbb50944:/bsd/hfs/hfs_hotfiles.c diff --git a/bsd/hfs/hfs_hotfiles.c b/bsd/hfs/hfs_hotfiles.c index fa59c27e0..7ba80c737 100644 --- a/bsd/hfs/hfs_hotfiles.c +++ b/bsd/hfs/hfs_hotfiles.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2003-2013 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -49,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). @@ -123,7 +129,7 @@ static void hf_printtree (hotfile_entry_t *); static int hotfiles_collect (struct hfsmount *); static int hotfiles_age (struct hfsmount *); static int hotfiles_adopt (struct hfsmount *); -static int hotfiles_evict (struct hfsmount *, struct proc *); +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 *); @@ -132,7 +138,7 @@ 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 *); @@ -140,9 +146,6 @@ static int hfc_comparekeys (HotFileKey *, HotFileKey *); char hfc_tag[] = "CLUSTERED HOT FILES B-TREE "; -extern int UBCINFOEXISTS(struct vnode * vp); -extern int hfs_vnop_write(struct vnop_write_args *ap); - /* *======================================================================== @@ -189,7 +192,7 @@ hfs_recording_start(struct hfsmount *hfsmp) FREE(tmp, M_TEMP); } - microuptime(&tv); + microtime(&tv); /* Times are base on GMT time. */ /* * On first startup check for suspended recording. @@ -204,10 +207,14 @@ hfs_recording_start(struct hfsmount *hfsmp) (SWAP_BE32 (hotfileinfo.timeleft) > 0) && (SWAP_BE32 (hotfileinfo.timebase) > 0)) { hfsmp->hfc_maxfiles = SWAP_BE32 (hotfileinfo.maxfilecnt); - hfsmp->hfc_timeout = SWAP_BE32 (hotfileinfo.timeleft) + tv.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("Resume recording hot files on %s (%d secs left)\n", + printf("hfs: Resume recording hot files on %s (%d secs left)\n", hfsmp->vcbVN, SWAP_BE32 (hotfileinfo.timeleft)); #endif } else { @@ -233,7 +240,7 @@ hfs_recording_start(struct hfsmount *hfsmp) return (error); } #if HFC_VERBOSE - printf("HFS: begin recording hot files on %s\n", hfsmp->vcbVN); + printf("hfs: begin recording hot files on %s\n", hfsmp->vcbVN); #endif hfsmp->hfc_maxfiles = HFC_DEFAULT_FILE_COUNT; hfsmp->hfc_timeout = tv.tv_sec + HFC_DEFAULT_DURATION; @@ -257,6 +264,13 @@ hfs_recording_start(struct hfsmount *hfsmp) 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++) @@ -294,12 +308,10 @@ hfs_recording_stop(struct hfsmount *hfsmp) if (hfsmp->hfc_stage != HFC_RECORDING) return (EPERM); - hotfiles_collect(hfsmp); + 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.... @@ -307,7 +319,7 @@ hfs_recording_stop(struct hfsmount *hfsmp) * then dump the sample data */ #if HFC_VERBOSE - printf("HFS: end of hot file recording on %s\n", hfsmp->vcbVN); + printf("hfs: end of hot file recording on %s\n", hfsmp->vcbVN); #endif hotdata = (hotfile_data_t *)hfsmp->hfc_recdata; if (hotdata == NULL) @@ -317,7 +329,7 @@ hfs_recording_stop(struct hfsmount *hfsmp) 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. @@ -329,7 +341,7 @@ hfs_recording_stop(struct hfsmount *hfsmp) /* 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) { @@ -352,10 +364,17 @@ hfs_recording_stop(struct hfsmount *hfsmp) 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); /* NOTE: destroys hot file tree! */ - microuptime(&tv); + microtime(&tv); listp->hfl_duration = tv.tv_sec - hfsmp->hfc_timebase; hfsmp->hfc_recdata = listp; @@ -395,9 +414,9 @@ hfs_recording_stop(struct hfsmount *hfsmp) 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); @@ -409,7 +428,6 @@ out: /* * Suspend recording the hotest files on a file system. */ -__private_extern__ int hfs_recording_suspend(struct hfsmount *hfsmp) { @@ -438,7 +456,7 @@ hfs_recording_suspend(struct hfsmount *hfsmp) hfsmp->hfc_stage = HFC_BUSY; #if HFC_VERBOSE - printf("HFS: suspend hot file recording on %s\n", hfsmp->vcbVN); + printf("hfs: suspend hot file recording on %s\n", hfsmp->vcbVN); #endif error = hfc_btree_open(hfsmp, &hfsmp->hfc_filevp); if (error) { @@ -450,12 +468,12 @@ hfs_recording_suspend(struct hfsmount *hfsmp) error = EINVAL; goto out; } - if (hfs_lock(VTOC(hfsmp->hfc_filevp), HFS_EXCLUSIVE_LOCK) != 0) { + if (hfs_lock(VTOC(hfsmp->hfc_filevp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT) != 0) { error = EPERM; - goto out; + goto end_transaction; } - microuptime(&tv); + microtime(&tv); hotfileinfo.magic = SWAP_BE32 (HFC_MAGIC); hotfileinfo.version = SWAP_BE32 (HFC_VERSION); hotfileinfo.duration = SWAP_BE32 (HFC_DEFAULT_DURATION); @@ -464,11 +482,14 @@ hfs_recording_suspend(struct hfsmount *hfsmp) 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)); hfs_unlock(VTOC(hfsmp->hfc_filevp)); + +end_transaction: hfs_end_transaction(hfsmp); + out: if (hfsmp->hfc_filevp) { (void) hfc_btree_close(hfsmp, hfsmp->hfc_filevp); @@ -480,7 +501,7 @@ out: } hfsmp->hfc_stage = HFC_DISABLED; wakeup((caddr_t)&hfsmp->hfc_stage); -exit: + lck_mtx_unlock(&hfsmp->hfc_mutex); return (error); } @@ -489,7 +510,6 @@ exit: /* * */ -__private_extern__ int hfs_recording_init(struct hfsmount *hfsmp) { @@ -498,7 +518,7 @@ hfs_recording_init(struct hfsmount *hfsmp) u_int32_t dataSize; HFSPlusCatalogFile *filep; BTScanState scanstate; - BTreeIterator * iterator; + BTreeIterator * iterator = NULL; FSBufferDescriptor record; HotFileKey * key; filefork_t * filefork; @@ -518,6 +538,16 @@ hfs_recording_init(struct hfsmount *hfsmp) 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. */ @@ -527,26 +557,37 @@ hfs_recording_init(struct hfsmount *hfsmp) hfsmp->hfc_stage = HFC_IDLE; return (0); } + + if (hfs_start_transaction(hfsmp) != 0) { + return EINVAL; + } + error = hfc_btree_create(hfsmp, HFSTOVCB(hfsmp)->blockSize, HFC_DEFAULT_FILE_COUNT); if (error) { #if HFC_VERBOSE - printf("Error %d creating hot file b-tree on %s \n", error, hfsmp->vcbVN); + printf("hfs: Error %d creating hot file b-tree on %s \n", error, hfsmp->vcbVN); #endif - return (error); + 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) { #if HFC_VERBOSE - printf("Error %d opening hot file b-tree on %s \n", error, hfsmp->vcbVN); + printf("hfs: Error %d opening hot file b-tree on %s \n", error, hfsmp->vcbVN); #endif - return (error); + 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; @@ -555,7 +596,7 @@ hfs_recording_init(struct hfsmount *hfsmp) 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. @@ -574,9 +615,9 @@ hfs_recording_init(struct hfsmount *hfsmp) error = EINVAL; goto out1; } - if (hfs_lock(VTOC(hfsmp->hfc_filevp), HFS_EXCLUSIVE_LOCK) != 0) { + if (hfs_lock(VTOC(hfsmp->hfc_filevp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT) != 0) { error = EPERM; - goto out1; + goto out0; } filefork = VTOF(hfsmp->hfc_filevp); @@ -650,15 +691,18 @@ hfs_recording_init(struct hfsmount *hfsmp) (void) BTFlushPath(filefork); hfs_unlock(VTOC(hfsmp->hfc_filevp)); +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; @@ -672,9 +716,8 @@ 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 (hfsmp->hfc_stage) { struct timeval tv; @@ -687,13 +730,13 @@ hfs_hotfilesync(struct hfsmount *hfsmp, struct proc *p) break; case HFC_RECORDING: - microuptime(&tv); + 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: @@ -719,7 +762,6 @@ hfs_hotfilesync(struct hfsmount *hfsmp, struct proc *p) * * Note: the cnode is locked on entry. */ -__private_extern__ int hfs_addhotfile(struct vnode *vp) { @@ -750,9 +792,17 @@ hfs_addhotfile_internal(struct vnode *vp) if (hfsmp->hfc_stage != HFC_RECORDING) return (0); - if ((!vnode_isreg(vp) && !vnode_islnk(vp)) || vnode_issystem(vp)) { + /* + * 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); @@ -765,9 +815,10 @@ hfs_addhotfile_internal(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); } @@ -806,7 +857,6 @@ hfs_addhotfile_internal(struct vnode *vp) * * Note: the cnode is locked on entry. */ -__private_extern__ int hfs_removehotfile(struct vnode *vp) { @@ -820,7 +870,7 @@ hfs_removehotfile(struct vnode *vp) if (hfsmp->hfc_stage != HFC_RECORDING) return (0); - if ((!vnode_isreg(vp) && !vnode_islnk(vp)) || vnode_issystem(vp)) { + if ((!vnode_isreg(vp)) || vnode_issystem(vp)) { return (0); } @@ -828,7 +878,7 @@ hfs_removehotfile(struct vnode *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); } @@ -862,7 +912,7 @@ out: static int hotfiles_collect_callback(struct vnode *vp, __unused void *cargs) { - if ((vnode_isreg(vp) || vnode_islnk(vp)) && !vnode_issystem(vp)) + if ((vnode_isreg(vp)) && !vnode_issystem(vp)) (void) hfs_addhotfile_internal(vp); return (VNODE_RETURNED); @@ -911,7 +961,7 @@ update_callback(const HotFileKey *key, u_int32_t *data, u_int32_t *state) static int hotfiles_refine(struct hfsmount *hfsmp) { - BTreeIterator * iterator; + BTreeIterator * iterator = NULL; struct mount *mp; filefork_t * filefork; hotfilelist_t *listp; @@ -928,6 +978,10 @@ hotfiles_refine(struct hfsmount *hfsmp) 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; @@ -939,9 +993,9 @@ hotfiles_refine(struct hfsmount *hfsmp) error = EINVAL; goto out; } - if (hfs_lock(VTOC(hfsmp->hfc_filevp), HFS_EXCLUSIVE_LOCK) != 0) { + if (hfs_lock(VTOC(hfsmp->hfc_filevp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT) != 0) { error = EPERM; - goto out; + goto out1; } filefork = VTOF(hfsmp->hfc_filevp); @@ -965,7 +1019,7 @@ hotfiles_refine(struct hfsmount *hfsmp) (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; } @@ -981,7 +1035,7 @@ hotfiles_refine(struct hfsmount *hfsmp) (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; } @@ -991,7 +1045,7 @@ hotfiles_refine(struct hfsmount *hfsmp) key->forkType = 0; 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; } @@ -1007,9 +1061,11 @@ hotfiles_refine(struct hfsmount *hfsmp) (void) BTFlushPath(filefork); hfs_unlock(VTOC(hfsmp->hfc_filevp)); +out1: hfs_end_transaction(hfsmp); out: - FREE(iterator, M_TEMP); + if (iterator) + FREE(iterator, M_TEMP); return (error); } @@ -1021,7 +1077,7 @@ out: static int hotfiles_adopt(struct hfsmount *hfsmp) { - BTreeIterator * iterator; + BTreeIterator * iterator = NULL; struct vnode *vp; filefork_t * filefork; hotfilelist_t *listp; @@ -1042,10 +1098,16 @@ hotfiles_adopt(struct hfsmount *hfsmp) if (hfsmp->hfc_stage != HFC_ADOPTION) { return (EBUSY); } - if (hfs_lock(VTOC(hfsmp->hfc_filevp), HFS_EXCLUSIVE_LOCK) != 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; @@ -1054,7 +1116,6 @@ hotfiles_adopt(struct hfsmount *hfsmp) 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; @@ -1076,7 +1137,7 @@ hotfiles_adopt(struct hfsmount *hfsmp) /* * Acquire a vnode for this file. */ - error = hfs_vget(hfsmp, listp->hfl_hotfile[i].hf_fileid, &vp, 0); + error = hfs_vget(hfsmp, listp->hfl_hotfile[i].hf_fileid, &vp, 0, 0); if (error) { if (error == ENOENT) { error = 0; @@ -1085,8 +1146,9 @@ hotfiles_adopt(struct hfsmount *hfsmp) } break; } - if (!vnode_isreg(vp) && !vnode_islnk(vp)) { - printf("hotfiles_adopt: huh, not a file %d (%d)\n", listp->hfl_hotfile[i].hf_fileid, VTOC(vp)->c_cnid); + 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; @@ -1116,26 +1178,19 @@ hotfiles_adopt(struct hfsmount *hfsmp) vnode_put(vp); break; /* adopt this entry the next time around */ } - /* Start a new transaction. */ - if (hfs_start_transaction(hfsmp) != 0) { - error = EINVAL; - hfs_unlock(VTOC(vp)); - vnode_put(vp); - break; - } - startedtrans = 1; - if (VTOC(vp)->c_desc.cd_nameptr) - data = *(u_int32_t *)(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, kauth_cred_get(), current_proc()); hfs_unlock(VTOC(vp)); vnode_put(vp); - if (error) - break; - + 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; @@ -1146,9 +1201,16 @@ hotfiles_adopt(struct hfsmount *hfsmp) key->fileID = listp->hfl_hotfile[i].hf_fileid; key->forkType = 0; + /* 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; @@ -1162,7 +1224,7 @@ hotfiles_adopt(struct hfsmount *hfsmp) data = listp->hfl_hotfile[i].hf_temperature; 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; @@ -1182,14 +1244,14 @@ hotfiles_adopt(struct hfsmount *hfsmp) } 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) { @@ -1201,8 +1263,8 @@ hotfiles_adopt(struct hfsmount *hfsmp) 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; } @@ -1223,9 +1285,9 @@ hotfiles_adopt(struct hfsmount *hfsmp) * 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; + BTreeIterator * iterator = NULL; struct vnode *vp; HotFileKey * key; filefork_t * filefork; @@ -1246,17 +1308,22 @@ 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) != 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; filesmoved = blksmoved = 0; bt_op = kBTreeFirstRecord; - MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK); bzero(iterator, sizeof(*iterator)); key = (HotFileKey*) &iterator->key; @@ -1271,20 +1338,20 @@ hotfiles_evict(struct hfsmount *hfsmp, struct proc *p) */ 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; @@ -1293,34 +1360,28 @@ hotfiles_evict(struct hfsmount *hfsmp, struct proc *p) /* * Aquire the vnode for this file. */ - error = hfs_vget(hfsmp, key->fileID, &vp, 0); - - /* Start a new transaction. */ - if (hfs_start_transaction(hfsmp) != 0) { - if (error == 0) { - hfs_unlock(VTOC(vp)); - vnode_put(vp); - } - error = EINVAL; - break; - } - startedtrans = 1; - + error = hfs_vget(hfsmp, key->fileID, &vp, 0, 0); if (error) { if (error == ENOENT) { goto delete; /* stale entry, go to next */ } else { - printf("hotfiles_evict: err %d getting file %d\n", + printf("hfs: hotfiles_evict: err %d getting file %d\n", error, key->fileID); } break; } - if (!vnode_isreg(vp) && !vnode_islnk(vp)) { - printf("hotfiles_evict: huh, not a file %d\n", key->fileID); + + /* + * 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) { @@ -1333,7 +1394,7 @@ 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 hfs_unlock(VTOC(vp)); vnode_put(vp); @@ -1343,9 +1404,9 @@ hotfiles_evict(struct hfsmount *hfsmp, struct proc *p) /* * Relocate file out of hot area. */ - error = hfs_relocate(vp, HFSTOVCB(hfsmp)->nextAllocation, proc_ucred(p), p); + error = hfs_relocate(vp, HFSTOVCB(hfsmp)->nextAllocation, vfs_context_ucred(ctx), vfs_context_proc(ctx)); if (error) { - printf("hotfiles_evict: err %d relocating file %d\n", error, key->fileID); + printf("hfs: hotfiles_evict: err %d relocating file %d\n", error, key->fileID); hfs_unlock(VTOC(vp)); vnode_put(vp); bt_op = kBTreeNextRecord; @@ -1369,6 +1430,13 @@ hotfiles_evict(struct hfsmount *hfsmp, struct proc *p) 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) { error = MacToVFSError(error); @@ -1394,7 +1462,7 @@ next: } /* 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) { @@ -1410,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); @@ -1426,7 +1494,7 @@ static int hotfiles_age(struct hfsmount *hfsmp) { BTreeInfoRec btinfo; - BTreeIterator * iterator; + BTreeIterator * iterator = NULL; BTreeIterator * prev_iterator; FSBufferDescriptor record; FSBufferDescriptor prev_record; @@ -1444,6 +1512,10 @@ hotfiles_age(struct hfsmount *hfsmp) 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; @@ -1464,7 +1536,7 @@ hotfiles_age(struct hfsmount *hfsmp) error = EINVAL; goto out2; } - if (hfs_lock(VTOC(hfsmp->hfc_filevp), HFS_EXCLUSIVE_LOCK) != 0) { + if (hfs_lock(VTOC(hfsmp->hfc_filevp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT) != 0) { error = EPERM; goto out1; } @@ -1572,7 +1644,8 @@ out: out1: hfs_end_transaction(hfsmp); out2: - FREE(iterator, M_TEMP); + if (iterator) + FREE(iterator, M_TEMP); return (error); } @@ -1618,7 +1691,7 @@ hotextents(struct hfsmount *hfsmp, HFSPlusExtentDescriptor * extents) static int hfc_btree_open(struct hfsmount *hfsmp, struct vnode **vpp) { - struct proc *p; + proc_t p; struct vnode *vp; struct cat_desc cdesc; struct cat_attr cattr; @@ -1627,36 +1700,38 @@ hfc_btree_open(struct hfsmount *hfsmp, struct vnode **vpp) 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); lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK); - error = cat_lookup(hfsmp, &cdesc, 0, &cdesc, &cattr, &cfork, NULL); + error = cat_lookup(hfsmp, &cdesc, 0, 0, &cdesc, &cattr, &cfork, NULL); 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, 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 (!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 hfs_unlock(VTOC(vp)); vnode_recycle(vp); @@ -1670,7 +1745,7 @@ 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); } @@ -1682,10 +1757,7 @@ again: vnode_put(vp); if (!vnode_issystem(vp)) - 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); + panic("hfs: hfc_btree_open: not a system file (vp = %p)", vp); return (error); } @@ -1698,16 +1770,16 @@ again: static int hfc_btree_close(struct hfsmount *hfsmp, struct vnode *vp) { - struct proc *p = current_proc(); + proc_t p = current_proc(); int error = 0; if (hfsmp->jnl) { - journal_flush(hfsmp->jnl); + hfs_journal_flush(hfsmp, FALSE); } if (vnode_get(vp) == 0) { - error = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK); + 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)); @@ -1726,30 +1798,27 @@ 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 vnode *dvp = NULL; struct vnode *vp = NULL; struct cnode *cp = NULL; - struct vfs_context context; + vfs_context_t ctx = vfs_context_current(); struct vnode_attr va; struct componentname cname; static char filename[] = HFC_FILENAME; int error; - context.vc_proc = current_proc(); - context.vc_ucred = kauth_cred_get(); - 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); - error = VFS_ROOT(HFSTOVFS(hfsmp), &dvp, &context); + error = VFS_ROOT(HFSTOVFS(hfsmp), &dvp, ctx); if (error) { return (error); } cname.cn_nameiop = CREATE; cname.cn_flags = ISLASTCN; - cname.cn_context = &context; + cname.cn_context = ctx; cname.cn_pnbuf = filename; cname.cn_pnlen = sizeof(filename); cname.cn_nameptr = filename; @@ -1763,30 +1832,35 @@ hfc_btree_create(struct hfsmount *hfsmp, int nodesize, int entries) 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, &context); + error = VNOP_CREATE(dvp, &vp, &cname, &va, ctx); if (error) { - printf("HFS: error %d creating HFBT on %s\n", error, HFSTOVCB(hfsmp)->vcbVN); + 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))) { + 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 (!vnode_isreg(vp) || cp->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 < (u_int64_t)nodesize) { + if (VTOF(vp)->ff_size < nodesize) { caddr_t buffer; u_int16_t *index; u_int16_t offset; @@ -1808,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); @@ -1824,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); @@ -1836,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); @@ -1845,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); @@ -1856,9 +1931,9 @@ hfc_btree_create(struct hfsmount *hfsmp, int nodesize, int entries) index[(nodesize / 2) - 4] = SWAP_BE16 (offset); vnode_setnoflush(vp); - error = hfs_truncate(vp, (off_t)filesize, IO_NDELAY, 0, &context); + 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); + printf("hfs: error %d growing HFBT on %s\n", error, HFSTOVCB(hfsmp)->vcbVN); goto out; } cp->c_flag |= C_ZFWANTSYNC; @@ -1868,27 +1943,28 @@ hfc_btree_create(struct hfsmount *hfsmp, int nodesize, int entries) struct vnop_write_args args; uio_t auio; - auio = uio_create(1, 0, UIO_SYSSPACE32, UIO_WRITE); + 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 = &context; + 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); + 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: + hfs_end_transaction(hfsmp); if (dvp) { vnode_put(dvp); } @@ -2178,7 +2254,7 @@ hf_getsortedlist(hotfile_data_t * hotdata, hotfilelist_t *sortedlist) sortedlist->hfl_count = i; #if HFC_VERBOSE - printf("HFS: hf_getsortedlist returned %d entries\n", i); + printf("hfs: hf_getsortedlist returned %d entries\n", i); #endif } @@ -2201,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); } }