/*
- * Copyright (c) 2003-2005 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 <sys/param.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/ubc.h>
+#include <sys/ubc_internal.h>
#include <sys/vnode.h>
#include <sys/vnode_internal.h>
#include <sys/kauth.h>
#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).
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 *);
/*
* 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 *);
char hfc_tag[] = "CLUSTERED HOT FILES B-TREE ";
-extern int UBCINFOEXISTS(struct vnode * vp);
-extern int hfs_vnop_write(struct vnop_write_args *ap);
-
/*
*========================================================================
FREE(tmp, M_TEMP);
}
- microuptime(&tv);
+ microtime(&tv); /* Times are base on GMT time. */
/*
* On first startup check for suspended recording.
(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 {
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;
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++)
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....
* 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)
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.
/* 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) {
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;
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);
/*
* Suspend recording the hotest files on a file system.
*/
-__private_extern__
int
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) {
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);
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);
}
hfsmp->hfc_stage = HFC_DISABLED;
wakeup((caddr_t)&hfsmp->hfc_stage);
-exit:
+
lck_mtx_unlock(&hfsmp->hfc_mutex);
return (error);
}
/*
*
*/
-__private_extern__
int
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;
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.
*/
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;
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.
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);
(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;
/*
* 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;
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:
*
* Note: the cnode is locked on entry.
*/
-__private_extern__
int
hfs_addhotfile(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);
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);
}
*
* Note: the cnode is locked on entry.
*/
-__private_extern__
int
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);
}
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);
}
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);
static int
hotfiles_refine(struct hfsmount *hfsmp)
{
- BTreeIterator * iterator;
+ BTreeIterator * iterator = NULL;
struct mount *mp;
filefork_t * filefork;
hotfilelist_t *listp;
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;
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);
(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;
}
(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;
}
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;
}
(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);
}
static int
hotfiles_adopt(struct hfsmount *hfsmp)
{
- BTreeIterator * iterator;
+ BTreeIterator * iterator = NULL;
struct vnode *vp;
filefork_t * filefork;
hotfilelist_t *listp;
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;
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;
/*
* 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;
}
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;
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;
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;
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;
}
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) {
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;
}
* 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;
hotfilelist_t *listp;
enum hfc_stage stage;
+ u_int32_t savedtemp;
int blksmoved;
int filesmoved;
int fileblocks;
int error = 0;
int startedtrans = 0;
+ int bt_op;
if (hfsmp->hfc_stage != HFC_EVICTION) {
return (EBUSY);
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;
/*
* 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;
/*
* 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) {
- (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\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);
- (void) BTDeleteRecord(filefork, iterator);
- key->temperature = HFC_LOOKUPTAG;
- (void) BTDeleteRecord(filefork, iterator);
- goto next; /* invalid entry, go to next */
+ goto delete; /* invalid entry, go to next */
}
+
fileblocks = VTOF(vp)->ff_blocks;
if ((blksmoved > 0) &&
(blksmoved + fileblocks) > HFC_BLKSPERSYNC) {
*/
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);
- (void) BTDeleteRecord(filefork, iterator);
- key->temperature = HFC_LOOKUPTAG;
- (void) BTDeleteRecord(filefork, iterator);
- goto next; /* go to next */
+ goto delete; /* stale entry, go to next */
}
/*
* 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;
goto next; /* go to next */
}
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);
} /* 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) {
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);
hotfiles_age(struct hfsmount *hfsmp)
{
BTreeInfoRec btinfo;
- BTreeIterator * iterator;
+ BTreeIterator * iterator = NULL;
BTreeIterator * prev_iterator;
FSBufferDescriptor record;
FSBufferDescriptor prev_record;
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;
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;
}
out1:
hfs_end_transaction(hfsmp);
out2:
- FREE(iterator, M_TEMP);
+ if (iterator)
+ FREE(iterator, M_TEMP);
return (error);
}
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;
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);
/* 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);
}
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);
}
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));
*
*/
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;
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;
goto out;
}
bzero(buffer, nodesize);
- index = (int16_t *)buffer;
+ index = (u_int16_t *)buffer;
entirespernode = (nodesize - sizeof(BTNodeDescriptor) - 2) /
(sizeof(HotFileKey) + 6);
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);
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);
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);
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;
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);
}
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
}
{
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);
}
}