return (0);
}
+#if defined(__APPLE__)
+/* dtrace_priv_proc() omitting the P_LNOATTACH check. For PID and EXECNAME accesses. */
+static int
+dtrace_priv_proc_relaxed(dtrace_state_t *state)
+{
+
+ if (state->dts_cred.dcr_action & DTRACE_CRA_PROC)
+ return (1);
+
+ cpu_core[CPU->cpu_id].cpuc_dtrace_flags |= CPU_DTRACE_UPRIV;
+
+ return (0);
+}
+#endif /* __APPLE__ */
+
static int
dtrace_priv_kernel(dtrace_state_t *state)
{
#else
case DIF_VAR_PID:
- if (!dtrace_priv_proc(state))
+ if (!dtrace_priv_proc_relaxed(state))
return (0);
/*
return ((uint64_t)curthread->t_procp->p_ppid);
#else
case DIF_VAR_PPID:
- if (!dtrace_priv_proc(state))
+ if (!dtrace_priv_proc_relaxed(state))
return (0);
/*
mstate->dtms_scratch_base + mstate->dtms_scratch_size)
return 0;
- if (!dtrace_priv_proc(state))
+ if (!dtrace_priv_proc_relaxed(state))
return (0);
mstate->dtms_scratch_ptr += scratch_size;
/*
- * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
{
OSStatus retval = E_NONE;
struct buf *bp = NULL;
+ u_int8_t allow_empty_node;
+
+ /* If the btree block is being read using hint, it is
+ * fine for the swap code to find zeroed out nodes.
+ */
+ if (options & kGetBlockHint) {
+ allow_empty_node = true;
+ } else {
+ allow_empty_node = false;
+ }
if (options & kGetEmptyBlock) {
daddr64_t blkno;
* size once the B-tree control block is set up with the node size
* from the header record.
*/
- retval = hfs_swap_BTNode (block, vp, kSwapBTNodeHeaderRecordOnly);
+ retval = hfs_swap_BTNode (block, vp, kSwapBTNodeHeaderRecordOnly, allow_empty_node);
} else if (block->blockReadFromDisk) {
/*
* The node was just read from disk, so always swap/check it.
* This is necessary on big endian since the test below won't trigger.
*/
- retval = hfs_swap_BTNode (block, vp, kSwapBTNodeBigToHost);
+ retval = hfs_swap_BTNode (block, vp, kSwapBTNodeBigToHost, allow_empty_node);
} else if (*((u_int16_t *)((char *)block->buffer + (block->blockSize - sizeof (u_int16_t)))) == 0x0e00) {
/*
* The node was left in the cache in non-native order, so swap it.
* This only happens on little endian, after the node is written
* back to disk.
*/
- retval = hfs_swap_BTNode (block, vp, kSwapBTNodeBigToHost);
+ retval = hfs_swap_BTNode (block, vp, kSwapBTNodeBigToHost, allow_empty_node);
}
/*
block.blockReadFromDisk = (buf_fromcache(bp) == 0);
block.blockSize = buf_count(bp);
- // swap the data now that this node is ready to go to disk
- retval = hfs_swap_BTNode (&block, vp, kSwapBTNodeHostToBig);
+ /* Swap the data now that this node is ready to go to disk.
+ * We allow swapping of zeroed out nodes here because we might
+ * be writing node whose last record just got deleted.
+ */
+ retval = hfs_swap_BTNode (&block, vp, kSwapBTNodeHostToBig, true);
if (retval)
panic("btree_swap_node: about to write corrupt node!\n");
}
/*
* These Catalog functions allow access to the HFS Catalog (database).
- * The catalog b-tree lock must be aquired before calling any of these routines.
+ * The catalog b-tree lock must be acquired before calling any of these routines.
*/
/*
- * cat_lookup - lookup a catalog node using a cnode decriptor
+ * cat_lookup - lookup a catalog node using a cnode descriptor
*
* Note: The caller is responsible for releasing the output
* catalog descriptor (when supplied outdescp is non-null).
*/
if (v_type == VDIR) {
hfs_reldirhints(cp, 0);
- if (cp->c_flag & C_HARDLINK)
- hfs_relorigins(cp);
+ }
+
+ if (cp->c_flag & C_HARDLINK) {
+ hfs_relorigins(cp);
}
if (cp->c_datafork)
if (vnode_isdir(vp)) {
hfs_reldirhints(cp, 0);
}
+
+ if (cp->c_flag & C_HARDLINK) {
+ hfs_relorigins(cp);
+ }
}
/* Release the file fork and related data */
if (fp) {
typedef struct linkorigin linkorigin_t;
#define MAX_CACHED_ORIGINS 10
-
+#define MAX_CACHED_FILE_ORIGINS 8
/*
* The cnode is used to represent each active (or recently active)
/*
- * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
hfs_swap_BTNode (
BlockDescriptor *src,
vnode_t vp,
- enum HFSBTSwapDirection direction
+ enum HFSBTSwapDirection direction,
+ u_int8_t allow_empty_node
)
{
BTNodeDescriptor *srcDesc = src->buffer;
* Sanity check: must be even, and within the node itself.
*
* We may be called to swap an unused node, which contains all zeroes.
- * This is why we allow the record offset to be zero.
+ * Unused nodes are expected only when allow_empty_node is true.
+ * If it is false and record offset is zero, return error.
*/
- if ((srcOffs[i] & 1) || (srcOffs[i] < sizeof(BTNodeDescriptor) && srcOffs[i] != 0) || (srcOffs[i] >= src->blockSize)) {
+ if ((srcOffs[i] & 1) || (
+ (allow_empty_node == false) && (srcOffs[i] == 0)) ||
+ (srcOffs[i] < sizeof(BTNodeDescriptor) && srcOffs[i] != 0) ||
+ (srcOffs[i] >= src->blockSize)) {
printf("hfs_swap_BTNode: record #%d invalid offset (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]);
error = fsBTInvalidHeaderErr;
goto fail;
* Sanity check: must be even, and within the node itself.
*
* We may be called to swap an unused node, which contains all zeroes.
+ * This can happen when the last record from a node gets deleted.
* This is why we allow the record offset to be zero.
+ * Unused nodes are expected only when allow_empty_node is true
+ * (the caller should set it to true for kSwapBTNodeBigToHost).
*/
- if ((srcOffs[i] & 1) || (srcOffs[i] < sizeof(BTNodeDescriptor) && srcOffs[i] != 0) || (srcOffs[i] >= src->blockSize)) {
+ if ((srcOffs[i] & 1) ||
+ ((allow_empty_node == false) && (srcOffs[i] == 0)) ||
+ (srcOffs[i] < sizeof(BTNodeDescriptor) && srcOffs[i] != 0) ||
+ (srcOffs[i] >= src->blockSize)) {
panic("hfs_UNswap_BTNode: record #%d invalid offset (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]);
error = fsBTInvalidHeaderErr;
goto fail;
/*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000, 2002-2003, 2005-2008 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
kSwapBTNodeHeaderRecordOnly = 3
};
-int hfs_swap_BTNode (BlockDescriptor *src, vnode_t vp, enum HFSBTSwapDirection direction);
+int hfs_swap_BTNode (BlockDescriptor *src, vnode_t vp, enum HFSBTSwapDirection direction,
+ u_int8_t allow_empty_node);
#ifdef __cplusplus
}
goto out;
}
- /* Purge any cached origin entries for a directory hard link. */
- if (cndesc.cd_flags & CD_ISDIR) {
- hfs_relorigin(cp, dcp->c_fileid);
- if (dcp->c_fileid != dcp->c_cnid) {
- hfs_relorigin(cp, dcp->c_cnid);
- }
+ /* Purge any cached origin entries for a directory or file hard link. */
+ hfs_relorigin(cp, dcp->c_fileid);
+ if (dcp->c_fileid != dcp->c_cnid) {
+ hfs_relorigin(cp, dcp->c_cnid);
}
/* Delete the link record. */
}
/*
- * Cache the orgin of a directory hard link
+ * Cache the origin of a directory or file hard link
*
* cnode must be lock on entry
*/
linkorigin_t *origin = NULL;
void * thread = current_thread();
int count = 0;
+ int maxorigins = (S_ISDIR(cp->c_mode)) ? MAX_CACHED_ORIGINS : MAX_CACHED_FILE_ORIGINS;
/*
* Look for an existing origin first. If not found, create/steal one.
}
if (origin == NULL) {
/* Recycle the last (i.e., the oldest) if we have too many. */
- if (count > MAX_CACHED_ORIGINS) {
+ if (count > maxorigins) {
origin = TAILQ_LAST(&cp->c_originlist, hfs_originhead);
TAILQ_REMOVE(&cp->c_originlist, origin, lo_link);
} else {
}
/*
- * Release any cached origins for a directory hard link
+ * Release any cached origins for a directory or file hard link
*
* cnode must be lock on entry
*/
}
/*
- * Release a specific origin for a directory hard link
+ * Release a specific origin for a directory or file hard link
*
* cnode must be lock on entry
*/
}
/*
- * Test if a directory hard link has a cached origin
+ * Test if a directory or file hard link has a cached origin
*
* cnode must be lock on entry
*/
}
/*
- * Obtain the current parent cnid of a directory hard link
+ * Obtain the current parent cnid of a directory or file hard link
*
* cnode must be lock on entry
*/
}
/*
- * Obtain the current cnid of a directory hard link
+ * Obtain the current cnid of a directory or file hard link
*
* cnode must be lock on entry
*/
}
goto exit;
}
-
- /* Save the origin info of a directory link for future ".." requests. */
- if (S_ISDIR(attr.ca_mode) && (attr.ca_recflags & kHFSHasLinkChainMask)) {
+
+ /*
+ * Save the origin info for file and directory hardlinks. Directory hardlinks
+ * need the origin for '..' lookups, and file hardlinks need it to ensure that
+ * competing lookups do not cause us to vend different hardlinks than the ones requested.
+ * We want to restrict saving the cache entries to LOOKUP namei operations, since
+ * we're really doing this to protect getattr.
+ */
+ if ((cnp->cn_nameiop == LOOKUP) && (VTOC(tvp)->c_flag & C_HARDLINK)) {
hfs_savelinkorigin(VTOC(tvp), VTOC(dvp)->c_fileid);
}
*cnode_locked = 1;
replace_desc(cp, &desc);
hfs_systemfile_unlock(VTOHFS(dvp), lockflags);
}
+
+ /* Save the lookup result in the origin list for future lookups, but
+ * only if it was through a LOOKUP nameiop
+ */
+ if (cnp->cn_nameiop == LOOKUP) {
+ hfs_savelinkorigin(cp, dcp->c_fileid);
+ }
+
hfs_unlock(cp);
}
#if NAMEDRSRCFORK
/*
- * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
/* from bsd/vfs/vfs_cluster.c */
extern int is_file_clean(vnode_t vp, off_t filesize);
+/* from bsd/hfs/hfs_vfsops.c */
+extern int hfs_vfs_vget(struct mount *mp, ino64_t ino, struct vnode **vpp, vfs_context_t context);
static int hfs_clonelink(struct vnode *, int, kauth_cred_t, struct proc *);
static int hfs_clonefile(struct vnode *, int, int, int);
bufptr = (char *)ap->a_data;
cnid = strtoul(bufptr, NULL, 10);
- if ((error = hfs_vget(hfsmp, cnid, &file_vp, 1))) {
+ /* We need to call hfs_vfs_vget to leverage the code that will fix the
+ * origin list for us if needed, as opposed to calling hfs_vget, since
+ * we will need it for the subsequent build_path call.
+ */
+ if ((error = hfs_vfs_vget(HFSTOVFS(hfsmp), cnid, &file_vp, context))) {
return (error);
}
error = build_path(file_vp, bufptr, sizeof(pathname_t), &outlen, 0, context);
block.blockSize = buf_count(bp);
/* Endian un-swap B-Tree node */
- retval = hfs_swap_BTNode (&block, vp, kSwapBTNodeHostToBig);
+ retval = hfs_swap_BTNode (&block, vp, kSwapBTNodeHostToBig, false);
if (retval)
panic("hfs_vnop_bwrite: about to write corrupt node!\n");
}
lck_grp_t * hfs_rwlock_group;
extern struct vnodeopv_desc hfs_vnodeop_opv_desc;
+/* not static so we can re-use in hfs_readwrite.c for build_path */
+int hfs_vfs_vget(struct mount *mp, ino64_t ino, struct vnode **vpp, vfs_context_t context);
+
static int hfs_changefs(struct mount *mp, struct hfs_mount_args *args);
static int hfs_fhtovp(struct mount *mp, int fhlen, unsigned char *fhp, struct vnode **vpp, vfs_context_t context);
static int hfs_sysctl(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp,
user_addr_t newp, size_t newlen, vfs_context_t context);
static int hfs_unmount(struct mount *mp, int mntflags, vfs_context_t context);
-static int hfs_vfs_vget(struct mount *mp, ino64_t ino, struct vnode **vpp, vfs_context_t context);
static int hfs_vptofh(struct vnode *vp, int *fhlenp, unsigned char *fhp, vfs_context_t context);
static int hfs_reclaimspace(struct hfsmount *hfsmp, u_long startblk, u_long reclaimblks, vfs_context_t context);
struct cat_desc cndesc;
struct cat_attr cnattr;
struct hfs_changefs_cargs *args;
+ int lockflags;
+ int error;
args = (struct hfs_changefs_cargs *)cargs;
cp = VTOC(vp);
vcb = HFSTOVCB(args->hfsmp);
- if (cat_lookup(args->hfsmp, &cp->c_desc, 0, &cndesc, &cnattr, NULL, NULL)) {
+ lockflags = hfs_systemfile_lock(args->hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
+ error = cat_lookup(args->hfsmp, &cp->c_desc, 0, &cndesc, &cnattr, NULL, NULL);
+ hfs_systemfile_unlock(args->hfsmp, lockflags);
+ if (error) {
/*
* If we couldn't find this guy skip to the next one
*/
*
* hfs_changefs_callback will be called for each vnode
* hung off of this mount point
- * the vnode will be
- * properly referenced and unreferenced around the callback
+ *
+ * The vnode will be properly referenced and unreferenced
+ * around the callback
*/
cargs.hfsmp = hfsmp;
cargs.namefix = namefix;
{
struct cnode *cp;
struct hfs_reload_cargs *args;
+ int lockflags;
args = (struct hfs_reload_cargs *)cargs;
/*
datafork = cp->c_datafork ? &cp->c_datafork->ff_data : NULL;
/* lookup by fileID since name could have changed */
- if ((args->error = cat_idlookup(args->hfsmp, cp->c_fileid, 0, &desc, &cp->c_attr, datafork)))
+ lockflags = hfs_systemfile_lock(args->hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
+ args->error = cat_idlookup(args->hfsmp, cp->c_fileid, 0, &desc, &cp->c_attr, datafork);
+ hfs_systemfile_unlock(args->hfsmp, lockflags);
+ if (args->error) {
return (VNODE_RETURNED_DONE);
+ }
/* update cnode's catalog descriptor */
(void) replace_desc(cp, &desc);
return (ENOTSUP);
}
-
-static int
+/* hfs_vfs_vget is not static since it is used in hfs_readwrite.c to support the
+ * build_path ioctl. We use it to leverage the code below that updates the origin
+ * cache if necessary.
+ */
+int
hfs_vfs_vget(struct mount *mp, ino64_t ino, struct vnode **vpp, __unused vfs_context_t context)
{
int error;
+ int lockflags;
+ struct hfsmount *hfsmp;
- error = hfs_vget(VFSTOHFS(mp), (cnid_t)ino, vpp, 1);
+ hfsmp = VFSTOHFS(mp);
+
+ error = hfs_vget(hfsmp, (cnid_t)ino, vpp, 1);
if (error)
return (error);
/*
* ADLs may need to have their origin state updated
- * since build_path needs a valid parent.
+ * since build_path needs a valid parent. The same is true
+ * for hardlinked files as well. There isn't a race window here in re-acquiring
+ * the cnode lock since we aren't pulling any data out of the cnode; instead, we're
+ * going back to the catalog.
*/
- if (vnode_isdir(*vpp) &&
- (VTOC(*vpp)->c_flag & C_HARDLINK) &&
+ if ((VTOC(*vpp)->c_flag & C_HARDLINK) &&
(hfs_lock(VTOC(*vpp), HFS_EXCLUSIVE_LOCK) == 0)) {
cnode_t *cp = VTOC(*vpp);
struct cat_desc cdesc;
- if (!hfs_haslinkorigin(cp) &&
- (cat_findname(VFSTOHFS(mp), (cnid_t)ino, &cdesc) == 0)) {
- if (cdesc.cd_parentcnid !=
- VFSTOHFS(mp)->hfs_private_desc[DIR_HARDLINKS].cd_cnid) {
- hfs_savelinkorigin(cp, cdesc.cd_parentcnid);
+ if (!hfs_haslinkorigin(cp)) {
+ lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
+ error = cat_findname(hfsmp, (cnid_t)ino, &cdesc);
+ hfs_systemfile_unlock(hfsmp, lockflags);
+ if (error == 0) {
+ if ((cdesc.cd_parentcnid !=
+ hfsmp->hfs_private_desc[DIR_HARDLINKS].cd_cnid) &&
+ (cdesc.cd_parentcnid !=
+ hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid)) {
+ hfs_savelinkorigin(cp, cdesc.cd_parentcnid);
+ }
+ cat_releasedesc(&cdesc);
}
- cat_releasedesc(&cdesc);
}
hfs_unlock(cp);
}
cnid_t nextlinkid;
cnid_t prevlinkid;
struct cat_desc linkdesc;
+ int lockflags;
cnattr.ca_linkref = linkref;
*/
if ((hfs_lookuplink(hfsmp, linkref, &prevlinkid, &nextlinkid) == 0) &&
(nextlinkid != 0)) {
- if (cat_findname(hfsmp, nextlinkid, &linkdesc) == 0) {
+ lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
+ error = cat_findname(hfsmp, nextlinkid, &linkdesc);
+ hfs_systemfile_unlock(hfsmp, lockflags);
+ if (error == 0) {
cat_releasedesc(&cndesc);
bcopy(&linkdesc, &cndesc, sizeof(linkdesc));
}
error = hfs_getnewvnode(hfsmp, NULLVP, &cn, &cndesc, 0, &cnattr, &cnfork, &vp);
- if (error == 0 && (VTOC(vp)->c_flag & C_HARDLINK) && vnode_isdir(vp)) {
+ if ((error == 0) && (VTOC(vp)->c_flag & C_HARDLINK)) {
hfs_savelinkorigin(VTOC(vp), cndesc.cd_parentcnid);
}
FREE_ZONE(cn.cn_pnbuf, cn.cn_pnlen, M_NAMEI);
/* mark the volume dirty (clear clean unmount bit) */
vcb->vcbAtrb &= ~kHFSVolumeUnmountedMask;
- /*
- * all done with system files so we can unlock now...
- */
- hfs_unlock(VTOC(hfsmp->hfs_allocation_vp));
- hfs_unlock(VTOC(hfsmp->hfs_catalog_vp));
- hfs_unlock(VTOC(hfsmp->hfs_extents_vp));
-
if (error == noErr)
{
error = cat_idlookup(hfsmp, kHFSRootFolderID, 0, NULL, NULL, NULL);
MarkVCBDirty( vcb ); // mark VCB dirty so it will be written
}
}
+
+ /*
+ * all done with system files so we can unlock now...
+ */
+ hfs_unlock(VTOC(hfsmp->hfs_allocation_vp));
+ hfs_unlock(VTOC(hfsmp->hfs_catalog_vp));
+ hfs_unlock(VTOC(hfsmp->hfs_extents_vp));
+
goto CmdDone;
//-- Release any resources allocated so far before exiting with an error:
struct vnode *vp = ap->a_vp;
struct vnode_attr *vap = ap->a_vap;
- struct vnode *rvp = NULL;
+ struct vnode *rvp = NULLVP;
struct hfsmount *hfsmp;
struct cnode *cp;
uint64_t data_size;
}
if (cp->c_blocks - VTOF(vp)->ff_blocks) {
+ /* We deal with resource fork vnode iocount at the end of the function */
error = hfs_vgetrsrc(hfsmp, vp, &rvp, TRUE);
if (error) {
goto out;
}
-
rcp = VTOC(rvp);
if (rcp && rcp->c_rsrcfork) {
total_size += rcp->c_rsrcfork->ff_size;
* which are hardlink-ignorant, will ask for va_linkid.
*/
vap->va_fileid = (u_int64_t)cp->c_fileid;
- /* Hardlinked directories have multiple cnids and parents (one per link). */
- if ((v_type == VDIR) && (cp->c_flag & C_HARDLINK)) {
+ /*
+ * We need to use the origin cache for both hardlinked files
+ * and directories. Hardlinked directories have multiple cnids
+ * and parents (one per link). Hardlinked files also have their
+ * own parents and link IDs separate from the indirect inode number.
+ * If we don't use the cache, we could end up vending the wrong ID
+ * because the cnode will only reflect the link that was looked up most recently.
+ */
+ if (cp->c_flag & C_HARDLINK) {
vap->va_linkid = (u_int64_t)hfs_currentcnid(cp);
vap->va_parentid = (u_int64_t)hfs_currentparent(cp);
} else {
VNODE_ATTR_va_encoding | VNODE_ATTR_va_rdev |
VNODE_ATTR_va_data_size;
- /* if this is the root, let VFS to find out the mount name, which may be different from the real name */
+ /* If this is the root, let VFS to find out the mount name, which may be different from the real name.
+ * Otherwise, we need to just take care for hardlinked files, which need to be looked up, if necessary
+ */
if (VATTR_IS_ACTIVE(vap, va_name) && (cp->c_cnid != kHFSRootFolderID)) {
- /* Return the name for ATTR_CMN_NAME */
- if (cp->c_desc.cd_namelen == 0) {
- if ((cp->c_flag & C_HARDLINK) && ((cp->c_flag & C_DELETED) == 0 || (cp->c_linkcount > 1))) {
- cnid_t nextlinkid;
- cnid_t prevlinkid;
- struct vnode *file_vp;
-
- if ((error = hfs_lookuplink(hfsmp, cp->c_fileid, &prevlinkid, &nextlinkid))) {
- goto out;
- }
-
- //
- // don't bother trying to get a linkid that's the same
- // as the current cnid
- //
- if (nextlinkid == VTOC(vp)->c_cnid) {
- if (prevlinkid == VTOC(vp)->c_cnid) {
- hfs_unlock(cp);
- goto out2;
- } else {
- nextlinkid = prevlinkid;
- }
- }
-
- hfs_unlock(cp);
-
- if (nextlinkid == 0 || (error = hfs_vget(hfsmp, nextlinkid, &file_vp, 1))) {
- if (prevlinkid == 0 || (error = hfs_vget(hfsmp, prevlinkid, &file_vp, 1))) {
- goto out2;
- }
+ struct cat_desc linkdesc;
+ int lockflags;
+ int uselinkdesc = 0;
+ cnid_t nextlinkid = 0;
+ cnid_t prevlinkid = 0;
+
+ /* Get the name for ATTR_CMN_NAME. We need to take special care for hardlinks
+ * here because the info. for the link ID requested by getattrlist may be
+ * different than what's currently in the cnode. This is because the cnode
+ * will be filled in with the information for the most recent link ID that went
+ * through namei/lookup(). If there are competing lookups for hardlinks that point
+ * to the same inode, one (or more) getattrlists could be vended incorrect name information.
+ * Also, we need to beware of open-unlinked files which could have a namelen of 0. Note
+ * that if another hardlink sibling of this file is being unlinked, that could also thrash
+ * the name fields but it should *not* be treated like an open-unlinked file here.
+ */
+ if ((cp->c_flag & C_HARDLINK) &&
+ ((cp->c_desc.cd_namelen == 0) || (vap->va_linkid != cp->c_cnid))) {
+ /* If we have no name and our linkID is the raw inode number, then we may
+ * have an open-unlinked file. Go to the next link in this case.
+ */
+ if ((cp->c_desc.cd_namelen == 0) && (vap->va_linkid == cp->c_fileid)) {
+ if ((error = hfs_lookuplink(hfsmp, vap->va_linkid, &prevlinkid, &nextlinkid))) {
+ goto out;
+ }
}
-
- cp = VTOC(file_vp);
- if (hfs_lock(cp, HFS_SHARED_LOCK) == 0) {
- if (cp->c_desc.cd_namelen) {
- strlcpy(vap->va_name, (const char *)cp->c_desc.cd_nameptr, MAXPATHLEN);
- }
- hfs_unlock(cp);
- vnode_put(file_vp);
- goto out2;
+ else {
+ nextlinkid = vap->va_linkid;
}
-
- if (vnode_name(file_vp)) {
- strlcpy(vap->va_name, vnode_name(file_vp), MAXPATHLEN);
- } else {
- error = ENOENT;
+ /* Now probe the catalog for the linkID. Note that we don't know if we have
+ * the exclusive lock here for the cnode, so we can't just update the descriptor.
+ * Instead, we should just store the descriptor's value locally and then use it to pass
+ * out the name value as needed below.
+ */
+ if (nextlinkid) {
+ lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
+ error = cat_findname(hfsmp, nextlinkid, &linkdesc);
+ hfs_systemfile_unlock(hfsmp, lockflags);
+ if (error == 0) {
+ uselinkdesc = 1;
+ }
}
- vnode_put(file_vp);
- goto out2;
- } else {
- error = ENOENT;
- goto out;
- }
- } else {
- strlcpy(vap->va_name, (const char *)cp->c_desc.cd_nameptr, MAXPATHLEN);
- VATTR_SET_SUPPORTED(vap, va_name);
+ }
+
+ /* By this point, we either patched the name above, and the c_desc points
+ * to correct data, or it already did, in which case we just proceed by copying
+ * the name into the VAP. Note that we will never set va_name to supported if
+ * nextlinkid is never initialized. This could happen in the degenerate case above
+ * involving the raw inode number, where it has no nextlinkid. In this case, we will
+ * simply not export the name as supported.
+ */
+ if (uselinkdesc) {
+ strlcpy(vap->va_name, (const char *)linkdesc.cd_nameptr, MAXPATHLEN);
+ VATTR_SET_SUPPORTED(vap, va_name);
+ cat_releasedesc(&linkdesc);
+ }
+ else if (cp->c_desc.cd_namelen) {
+ strlcpy(vap->va_name, (const char *)cp->c_desc.cd_nameptr, MAXPATHLEN);
+ VATTR_SET_SUPPORTED(vap, va_name);
}
}
out:
hfs_unlock(cp);
-out2:
+ /*
+ * We need to drop the iocount on the rsrc fork vnode only *after* we've
+ * released the cnode lock, since vnode_put can trigger an inactive call, which
+ * will go back into the HFS and try to acquire a cnode lock.
+ */
if (rvp) {
vnode_put(rvp);
}
/*
- * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
++btreePtr->numReleaseNodes;
M_ExitOnError (err);
- err = GetNode (btreePtr, kHeaderNodeNum, &nodeRec );
+ err = GetNode (btreePtr, kHeaderNodeNum, 0, &nodeRec );
M_ExitOnError (err);
}
{
nodeNum = searchIterator->hint.nodeNum;
- err = GetNode (btreePtr, nodeNum, &node);
+ err = GetNode (btreePtr, nodeNum, kGetNodeHint, &node);
if( err == noErr )
{
if ( ((BTNodeDescriptor*) node.buffer)->kind == kBTLeafNode &&
goto ErrorExit;
}
- err = GetNode (btreePtr, nodeNum, &node);
+ err = GetNode (btreePtr, nodeNum, 0, &node);
M_ExitOnError (err);
if ( ((NodeDescPtr) node.buffer)->kind != kBTLeafNode ||
M_ExitOnError(err);
// Look up the left node
- err = GetNode (btreePtr, nodeNum, &left);
+ err = GetNode (btreePtr, nodeNum, 0, &left);
M_ExitOnError (err);
// Look up the current node again
nodeNum = ((NodeDescPtr) node.buffer)->fLink;
if ( nodeNum > 0)
{
- err = GetNode (btreePtr, nodeNum, &right);
+ err = GetNode (btreePtr, nodeNum, 0, &right);
M_ExitOnError (err);
} else {
err = fsBTEndOfIterationErr;
goto ErrorExit;
}
- err = GetNode(btreePtr, nodeNum, &node);
+ err = GetNode(btreePtr, nodeNum, 0, &node);
M_ExitOnError(err);
if ( ((NodeDescPtr)node.buffer)->kind != kBTLeafNode ||
M_ExitOnError(err);
// Look up the left node
- err = GetNode (btreePtr, nodeNum, &left);
+ err = GetNode (btreePtr, nodeNum, 0, &left);
M_ExitOnError (err);
// Look up the current node again
nodeNum = ((NodeDescPtr)node.buffer)->fLink;
if ( nodeNum > 0)
{
- err = GetNode(btreePtr, nodeNum, &right);
+ err = GetNode(btreePtr, nodeNum, 0, &right);
M_ExitOnError(err);
} else {
err = fsBTEndOfIterationErr;
nodeNum = ((NodeDescPtr)node.buffer)->fLink;
if ( nodeNum > 0)
{
- err = GetNode(btreePtr, nodeNum, &right);
+ err = GetNode(btreePtr, nodeNum, 0, &right);
M_ExitOnError(err);
} else {
err = fsBTEndOfIterationErr;
{
insertNodeNum = iterator->hint.nodeNum;
- err = GetNode (btreePtr, insertNodeNum, &nodeRec);
+ err = GetNode (btreePtr, insertNodeNum, kGetNodeHint, &nodeRec);
if( err == noErr )
{
// XXXdbg
{
insertNodeNum = iterator->hint.nodeNum;
- err = GetNode (btreePtr, insertNodeNum, &nodeRec);
+ err = GetNode (btreePtr, insertNodeNum, kGetNodeHint, &nodeRec);
if (err == noErr)
{
if (((NodeDescPtr)nodeRec.buffer)->kind == kBTLeafNode &&
REQUIRE_FILE_LOCK(btreePtr->fileRefNum, false);
- err = GetNode(btreePtr, kHeaderNodeNum, &node);
+ err = GetNode(btreePtr, kHeaderNodeNum, 0, &node);
if (err != noErr)
return (err);
REQUIRE_FILE_LOCK(btreePtr->fileRefNum, false);
- err = GetNode(btreePtr, kHeaderNodeNum, &node);
+ err = GetNode(btreePtr, kHeaderNodeNum, 0, &node);
if (err)
return (err);
REQUIRE_FILE_LOCK(btreePtr->fileRefNum, false);
- err = GetNode(btreePtr, kHeaderNodeNum, &node);
+ err = GetNode(btreePtr, kHeaderNodeNum, 0, &node);
if (err)
return (err);
/*
- * Copyright (c) 2000-2003, 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2003, 2005-2008 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
err = UpdateNode (btreePtr, &mapNode, 0, kLockTransaction);
M_ExitOnError (err);
- err = GetNode (btreePtr, nextNodeNum, &mapNode);
+ err = GetNode (btreePtr, nextNodeNum, 0, &mapNode);
M_ExitOnError (err);
// XXXdbg
err = ReleaseNode (btreePtr, nodePtr);
M_ExitOnError (err);
- err = GetNode (btreePtr, nextNodeNum, nodePtr);
+ err = GetNode (btreePtr, nextNodeNum, 0, nodePtr);
M_ExitOnError (err);
if ( ((NodeDescPtr)nodePtr->buffer)->kind != kBTMapNode)
++btreePtr->numMapNodesRead;
mapIndex = 0;
} else {
- err = GetNode (btreePtr, kHeaderNodeNum, nodePtr);
+ err = GetNode (btreePtr, kHeaderNodeNum, 0, nodePtr);
M_ExitOnError (err);
if ( ((NodeDescPtr)nodePtr->buffer)->kind != kBTHeaderNode)
/*
- * Copyright (c) 2000-2003, 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2003, 2005-2008 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
return noErr;
- err = GetNode (btreePtr, kHeaderNodeNum, &node );
+ err = GetNode (btreePtr, kHeaderNodeNum, 0, &node );
if (err != noErr) {
return err;
}
goto SearchTheTree;
}
- err = GetNode (btreePtr, nodeNum, middle);
+ err = GetNode (btreePtr, nodeNum, kGetNodeHint, middle);
if( err == fsBTInvalidNodeErr ) // returned if nodeNum is out of range
goto SearchTheTree;
M_ExitOnError(err);
// Look up the left node
- err = GetNode (btreePtr, nodeNum, left);
+ err = GetNode (btreePtr, nodeNum, 0, left);
M_ExitOnError (err);
// Look up the current node again
/*
- * Copyright (c) 2000, 2002, 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000, 2002, 2005-2008 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
OSStatus GetNode (BTreeControlBlockPtr btreePtr,
u_int32_t nodeNum,
+ u_int32_t flags,
NodeRec *nodePtr )
{
OSStatus err;
GetBlockProcPtr getNodeProc;
+ u_int32_t options;
- //\80\80 is nodeNum within proper range?
+ // is nodeNum within proper range?
if( nodeNum >= btreePtr->totalNodes )
{
Panic("\pGetNode:nodeNum >= totalNodes");
}
nodePtr->blockSize = btreePtr->nodeSize; // indicate the size of a node
+
+ options = kGetBlock;
+ if ( flags & kGetNodeHint )
+ {
+ options |= kGetBlockHint;
+ }
getNodeProc = btreePtr->getBlockProc;
err = getNodeProc (btreePtr->fileRefNum,
nodeNum,
- kGetBlock,
+ options,
nodePtr );
if (err != noErr)
{
Panic ("\pGetNode: getNodeProc returned error.");
- // nodePtr->buffer = nil;
goto ErrorExit;
}
++btreePtr->numGetNodes;
/*
- * Copyright (c) 1996-2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1996-2008 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
fref = scanState->btcb->fileRefNum;
- /* This node was read from disk, so it must be swapped/checked. */
- err = hfs_swap_BTNode(&block, fref, kSwapBTNodeBigToHost);
+ /* This node was read from disk, so it must be swapped/checked.
+ * Since we are reading multiple nodes, we might have read an
+ * unused node. Therefore we allow swapping of unused nodes.
+ */
+ err = hfs_swap_BTNode(&block, fref, kSwapBTNodeBigToHost, true);
if ( err != noErr ) {
printf("FindNextLeafNode: Error from hfs_swap_BTNode (node %u)\n", scanState->nodeNum);
continue;
/*
- * Copyright (c) 2000, 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
goto ErrorExit;
}
- err = GetNode (btreePtr, curNodeNum, &nodeRec);
+ err = GetNode (btreePtr, curNodeNum, 0, &nodeRec);
if (err != noErr)
{
goto ErrorExit;
PanicIf ( parentNodeNum == 0, "\p InsertLevel: parent node is zero!?");
- err = GetNode (btreePtr, parentNodeNum, &parentNode); // released as target node in next level up
+ err = GetNode (btreePtr, parentNodeNum, 0, &parentNode); // released as target node in next level up
M_ExitOnError (err);
#if defined(applec) && !defined(__SC__)
if (DEBUG_BUILD && level > 1)
if ( leftNode->buffer == nil )
{
- err = GetNode (btreePtr, leftNodeNum, leftNode); // will be released by caller or a split below
+ err = GetNode (btreePtr, leftNodeNum, 0, leftNode); // will be released by caller or a split below
M_ExitOnError (err);
// XXXdbg
ModifyBlockStart(btreePtr->fileRefNum, leftNode);
siblingNodeNum = targetNodePtr->bLink; // Left Sibling Node
if ( siblingNodeNum != 0 )
{
- err = GetNode (btreePtr, siblingNodeNum, &siblingNode);
+ err = GetNode (btreePtr, siblingNodeNum, 0, &siblingNode);
M_ExitOnError (err);
// XXXdbg
siblingNodeNum = targetNodePtr->fLink; // Right Sibling Node
if ( siblingNodeNum != 0 )
{
- err = GetNode (btreePtr, siblingNodeNum, &siblingNode);
+ err = GetNode (btreePtr, siblingNodeNum, 0, &siblingNode);
M_ExitOnError (err);
// XXXdbg
//// Get Parent Node and index
index = treePathTable [level].index;
- err = GetNode (btreePtr, treePathTable[level].node, &parentNode);
+ err = GetNode (btreePtr, treePathTable[level].node, 0, &parentNode);
M_ExitOnError (err);
if ( updateRequired )
M_ExitOnError (err);
//// Get New Root Node
- err = GetNode (btreePtr, btreePtr->rootNode, blockPtr);
+ err = GetNode (btreePtr, btreePtr->rootNode, 0, blockPtr);
M_ExitOnError (err);
// XXXdbg
/*
- * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
*/
enum {
kGetBlock = 0x00000000,
+ kGetBlockHint = 0x00000001, // if set, the block is being looked up using hint
kForceReadBlock = 0x00000002, //\80\80 how does this relate to Read/Verify? Do we need this?
kGetEmptyBlock = 0x00000008
};
/*
- * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
OSStatus GetNode (BTreeControlBlockPtr btreePtr,
u_int32_t nodeNum,
+ u_int32_t flags,
NodeRec *returnNodePtr );
+/* Flags for GetNode() */
+#define kGetNodeHint 0x1 /* If set, the node is being looked up using a hint */
+
OSStatus GetLeftSiblingNode (BTreeControlBlockPtr btreePtr,
NodeDescPtr node,
NodeRec *left );
-#define GetLeftSiblingNode(btree,node,left) GetNode ((btree), ((NodeDescPtr)(node))->bLink, (left))
+#define GetLeftSiblingNode(btree,node,left) GetNode ((btree), ((NodeDescPtr)(node))->bLink, 0, (left))
OSStatus GetRightSiblingNode (BTreeControlBlockPtr btreePtr,
NodeDescPtr node,
NodeRec *right );
-#define GetRightSiblingNode(btree,node,right) GetNode ((btree), ((NodeDescPtr)(node))->fLink, (right))
+#define GetRightSiblingNode(btree,node,right) GetNode ((btree), ((NodeDescPtr)(node))->fLink, 0, (right))
OSStatus GetNewNode (BTreeControlBlockPtr btreePtr,
/* all sysctl names at this level are name and field */
if (namelen != 2)
return (ENOTDIR); /* overloaded */
+ if (name[0] < 0 || name[0] >= CTL_DEBUG_MAXID)
+ return (ENOTSUP);
cdp = debugvars[name[0]];
if (cdp->debugname == 0)
return (ENOTSUP);
_state.pis_total += PTMX_GROW_VECTOR;
if (old_pis_ioctl_list)
FREE(old_pis_ioctl_list, M_TTYS);
+ }
+
+ if (_state.pis_ioctl_list[minor] != NULL) {
+ ttyfree(new_ptmx_ioctl->pt_tty);
+ DEVFS_UNLOCK();
+ FREE(new_ptmx_ioctl, M_TTYS);
+
+ /* Special error value so we know to redrive the open, we've been raced */
+ return (struct ptmx_ioctl*)-1;
+
}
/* Vector is large enough; grab a new ptmx_ioctl */
if (!(_state.pis_ioctl_list[minor]->pt_flags & (PF_OPEN_M|PF_OPEN_S))) {
/* Mark as free so it can be reallocated later */
old_ptmx_ioctl = _state.pis_ioctl_list[ minor];
- _state.pis_ioctl_list[ minor] = NULL;
- _state.pis_free++;
}
DEVFS_UNLOCK();
devfs_remove(old_ptmx_ioctl->pt_devhandle);
ttyfree(old_ptmx_ioctl->pt_tty);
FREE(old_ptmx_ioctl, M_TTYS);
+
+ /* Don't remove the entry until the devfs slot is free */
+ DEVFS_LOCK();
+ _state.pis_ioctl_list[ minor] = NULL;
+ _state.pis_free++;
+ DEVFS_UNLOCK();
}
return (0); /* Success */
int error = 0;
boolean_t funnel_state;
-
- if ((pti = ptmx_get_ioctl(minor(dev), PF_OPEN_M)) == NULL) {
+ pti = ptmx_get_ioctl(minor(dev), PF_OPEN_M);
+ if (pti == NULL) {
return (ENXIO);
+ } else if (pti == (struct ptmx_ioctl*)-1) {
+ return (EREDRIVEOPEN);
}
tp = pti->pt_tty;
#endif /* MAC_NET */
to->m_pkthdr = from->m_pkthdr; /* especially tags */
m_tag_init(from); /* purge tags from src */
- to->m_flags = from->m_flags & M_COPYFLAGS;
- to->m_data = (to)->m_pktdat;
+ to->m_flags = (from->m_flags & M_COPYFLAGS) | (to->m_flags & M_EXT);
+ if ((to->m_flags & M_EXT) == 0)
+ to->m_data = to->m_pktdat;
}
/*
#include <net/net_osdep.h>
+extern u_long route_generation;
+
int ip_gif_ttl = GIF_TTL;
SYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW,
&ip_gif_ttl, 0, "");
bcopy(&iphdr, mtod(m, struct ip *), sizeof(struct ip));
if (dst->sin_family != sin_dst->sin_family ||
- dst->sin_addr.s_addr != sin_dst->sin_addr.s_addr) {
+ dst->sin_addr.s_addr != sin_dst->sin_addr.s_addr ||
+ (sc->gif_ro.ro_rt != NULL &&
+ (sc->gif_ro.ro_rt->generation_id != route_generation ||
+ sc->gif_ro.ro_rt->rt_ifp == ifp))) {
/* cache route doesn't match */
dst->sin_family = sin_dst->sin_family;
dst->sin_len = sizeof(struct sockaddr_in);
m->m_pkthdr.rcvif = ifa->ifa_ifp;
ifafree(ifa);
}
-
- if ((~IF_HWASSIST_CSUM_FLAGS(m->m_pkthdr.rcvif->if_hwassist) &
- m->m_pkthdr.csum_flags) == 0) {
- if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
- m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
- }
- m->m_pkthdr.csum_flags |=
- CSUM_DATA_VALID | CSUM_PSEUDO_HDR |
- CSUM_IP_CHECKED | CSUM_IP_VALID;
- m->m_pkthdr.csum_data = 0xffff;
- }
- else if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
- int hlen;
-
-#ifdef _IP_VHL
- hlen = IP_VHL_HL(ip->ip_vhl) << 2;
-#else
- hlen = ip->ip_hl << 2;
-#endif
- in_delayed_cksum(m);
- m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
- ip->ip_sum = in_cksum(m, hlen);
- }
-
#if CONFIG_MACF_NET
mac_mbuf_label_associate_socket(so, m);
#endif
/* strip off the trailing pad area. */
m_adj(m, -taillen);
-
+ ip = mtod(m, struct ip *);
#ifdef IPLEN_FLIPPED
ip->ip_len = ip->ip_len - taillen;
#else
/* strip off the trailing pad area. */
m_adj(m, -taillen);
-
+ ip6 = mtod(m, struct ip6_hdr *);
ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - taillen);
/* was it transmitted over the IPsec tunnel SA? */
#include <net/net_osdep.h>
+extern u_long route_generation;
+
static __inline__ void*
_cast_non_const(const void * ptr) {
union {
ip6->ip6_flow |= htonl((u_int32_t)otos << 20);
if (dst->sin6_family != sin6_dst->sin6_family ||
- !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr)) {
+ !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr) ||
+ (sc->gif_ro6.ro_rt != NULL &&
+ (sc->gif_ro6.ro_rt->generation_id != route_generation ||
+ sc->gif_ro6.ro_rt->rt_ifp == ifp))) {
/* cache route doesn't match */
bzero(dst, sizeof(*dst));
dst->sin6_family = sin6_dst->sin6_family;
}
/* if it constitutes infinite encapsulation, punt. */
- if (sc->gif_ro.ro_rt->rt_ifp == ifp) {
+ if (sc->gif_ro6.ro_rt->rt_ifp == ifp) {
m_freem(m);
return ENETUNREACH; /*XXX*/
}
#define ERESTART (-1) /* restart syscall */
#define EJUSTRETURN (-2) /* don't modify regs, just return */
#define ERECYCLE (-5) /* restart lookup under heavy vnode pressure/recycling */
+#define EREDRIVEOPEN (-6)
#endif
#endif /* _SYS_ERRNO_H_ */
}
/* Ask the file system for its parent id and for its name (optional). */
ret = vnode_getattr(vp, &va, ctx);
+
if (fixhardlink) {
- if (vp->v_name || VATTR_IS_SUPPORTED(&va, va_name)) {
- if (ret == 0) {
- str = va.va_name;
- } else if (vp->v_name) {
- str = vp->v_name;
- ret = 0;
- } else {
- ret = ENOENT;
- goto bad_news;
- }
+ if ((ret == 0) && (VATTR_IS_SUPPORTED(&va, va_name))) {
+ str = va.va_name;
+ } else if (vp->v_name) {
+ str = vp->v_name;
+ ret = 0;
+ } else {
+ ret = ENOENT;
+ goto bad_news;
+ }
+ len = strlen(str);
- len = strlen(str);
-
- /* Check that there's enough space. */
- if ((end - buff) < (len + 1)) {
- ret = ENOSPC;
- } else {
- /* Copy the name backwards. */
- str += len;
-
- for (; len > 0; len--) {
- *--end = *--str;
- }
- /* Add a path separator. */
- *--end = '/';
+ /* Check that there's enough space. */
+ if ((end - buff) < (len + 1)) {
+ ret = ENOSPC;
+ } else {
+ /* Copy the name backwards. */
+ str += len;
+
+ for (; len > 0; len--) {
+ *--end = *--str;
}
+ /* Add a path separator. */
+ *--end = '/';
}
bad_news:
FREE_ZONE(va.va_name, MAXPATHLEN, M_NAMEI);
struct namecache *ncp;
kauth_cred_t tcred = NULL;
- if ((LIST_FIRST(&vp->v_nclinks) == NULL) && (LIST_FIRST(&vp->v_ncchildren) == NULL))
+ if ((LIST_FIRST(&vp->v_nclinks) == NULL) && (LIST_FIRST(&vp->v_ncchildren) == NULL) && (vp->v_cred == NOCRED))
return;
NAME_CACHE_LOCK();
long long zero_cnt1;
off_t zero_off1;
struct cl_extent cl;
- int intersection;
struct cl_writebehind *wbp;
int bflag;
u_int max_cluster_pgcount;
* to release the rest of the pages in the upl without modifying
* there state and mark the failed page in error
*/
- ubc_upl_abort_range(upl, 0, PAGE_SIZE, UPL_ABORT_DUMP_PAGES);
+ ubc_upl_abort_range(upl, 0, PAGE_SIZE, UPL_ABORT_DUMP_PAGES|UPL_ABORT_FREE_ON_EMPTY);
if (upl_size > PAGE_SIZE)
ubc_upl_abort_range(upl, 0, upl_size, UPL_ABORT_FREE_ON_EMPTY);
* need to release the rest of the pages in the upl without
* modifying there state and mark the failed page in error
*/
- ubc_upl_abort_range(upl, upl_offset, PAGE_SIZE, UPL_ABORT_DUMP_PAGES);
+ ubc_upl_abort_range(upl, upl_offset, PAGE_SIZE, UPL_ABORT_DUMP_PAGES|UPL_ABORT_FREE_ON_EMPTY);
if (upl_size > PAGE_SIZE)
ubc_upl_abort_range(upl, 0, upl_size, UPL_ABORT_FREE_ON_EMPTY);
*/
cluster_zero(upl, io_size, upl_size - io_size, NULL);
}
+ /*
+ * release the upl now if we hold one since...
+ * 1) pages in it may be present in the sparse cluster map
+ * and may span 2 separate buckets there... if they do and
+ * we happen to have to flush a bucket to make room and it intersects
+ * this upl, a deadlock may result on page BUSY
+ * 2) we're delaying the I/O... from this point forward we're just updating
+ * the cluster state... no need to hold the pages, so commit them
+ * 3) IO_SYNC is set...
+ * because we had to ask for a UPL that provides currenty non-present pages, the
+ * UPL has been automatically set to clear the dirty flags (both software and hardware)
+ * upon committing it... this is not the behavior we want since it's possible for
+ * pages currently present as part of a mapped file to be dirtied while the I/O is in flight.
+ * we'll pick these pages back up later with the correct behavior specified.
+ * 4) we don't want to hold pages busy in a UPL and then block on the cluster lock... if a flush
+ * of this vnode is in progress, we will deadlock if the pages being flushed intersect the pages
+ * we hold since the flushing context is holding the cluster lock.
+ */
+ ubc_upl_commit_range(upl, 0, upl_size,
+ UPL_COMMIT_SET_DIRTY | UPL_COMMIT_INACTIVATE | UPL_COMMIT_FREE_ON_EMPTY);
+check_cluster:
+ /*
+ * calculate the last logical block number
+ * that this delayed I/O encompassed
+ */
+ cl.e_addr = (daddr64_t)((upl_f_offset + (off_t)upl_size) / PAGE_SIZE_64);
+
if (flags & IO_SYNC)
/*
* if the IO_SYNC flag is set than we need to
* the I/O
*/
goto issue_io;
-check_cluster:
+
/*
* take the lock to protect our accesses
* of the writebehind and sparse cluster state
*/
wbp = cluster_get_wbp(vp, CLW_ALLOCATE | CLW_RETURNLOCKED);
- /*
- * calculate the last logical block number
- * that this delayed I/O encompassed
- */
- cl.e_addr = (daddr64_t)((upl_f_offset + (off_t)upl_size) / PAGE_SIZE_64);
-
if (wbp->cl_scmap) {
if ( !(flags & IO_NOCACHE)) {
/*
* we've fallen into the sparse
* cluster method of delaying dirty pages
- * first, we need to release the upl if we hold one
- * since pages in it may be present in the sparse cluster map
- * and may span 2 separate buckets there... if they do and
- * we happen to have to flush a bucket to make room and it intersects
- * this upl, a deadlock may result on page BUSY
*/
- if (upl_size)
- ubc_upl_commit_range(upl, 0, upl_size,
- UPL_COMMIT_SET_DIRTY | UPL_COMMIT_INACTIVATE | UPL_COMMIT_FREE_ON_EMPTY);
-
sparse_cluster_add(wbp, vp, &cl, newEOF, callback, callback_arg);
lck_mtx_unlock(&wbp->cl_lockw);
* to uncached writes on the file, so go ahead
* and push whatever's in the sparse map
* and switch back to normal clustering
- *
- * see the comment above concerning a possible deadlock...
*/
- if (upl_size) {
- ubc_upl_commit_range(upl, 0, upl_size,
- UPL_COMMIT_SET_DIRTY | UPL_COMMIT_INACTIVATE | UPL_COMMIT_FREE_ON_EMPTY);
- /*
- * setting upl_size to 0 keeps us from committing a
- * second time in the start_new_cluster path
- */
- upl_size = 0;
- }
- sparse_cluster_push(wbp, vp, newEOF, PUSH_ALL, callback, callback_arg);
-
wbp->cl_number = 0;
+
+ sparse_cluster_push(wbp, vp, newEOF, PUSH_ALL, callback, callback_arg);
/*
* no clusters of either type present at this point
* so just go directly to start_new_cluster since
*/
goto start_new_cluster;
}
- upl_offset = 0;
-
if (wbp->cl_number == 0)
/*
* no clusters currently present
*/
wbp->cl_clusters[cl_index].e_addr = wbp->cl_clusters[cl_index].b_addr + max_cluster_pgcount;
- if (upl_size) {
- daddr64_t start_pg_in_upl;
-
- start_pg_in_upl = (daddr64_t)(upl_f_offset / PAGE_SIZE_64);
-
- if (start_pg_in_upl < wbp->cl_clusters[cl_index].e_addr) {
- intersection = (int)((wbp->cl_clusters[cl_index].e_addr - start_pg_in_upl) * PAGE_SIZE);
-
- ubc_upl_commit_range(upl, upl_offset, intersection,
- UPL_COMMIT_SET_DIRTY | UPL_COMMIT_INACTIVATE | UPL_COMMIT_FREE_ON_EMPTY);
- upl_f_offset += intersection;
- upl_offset += intersection;
- upl_size -= intersection;
- }
- }
cl.b_addr = wbp->cl_clusters[cl_index].e_addr;
}
/*
*/
wbp->cl_clusters[cl_index].b_addr = wbp->cl_clusters[cl_index].e_addr - max_cluster_pgcount;
- if (upl_size) {
- intersection = (int)((cl.e_addr - wbp->cl_clusters[cl_index].b_addr) * PAGE_SIZE);
-
- if ((u_int)intersection > upl_size)
- /*
- * because the current write may consist of a number of pages found in the cache
- * which are not part of the UPL, we may have an intersection that exceeds
- * the size of the UPL that is also part of this write
- */
- intersection = upl_size;
-
- ubc_upl_commit_range(upl, upl_offset + (upl_size - intersection), intersection,
- UPL_COMMIT_SET_DIRTY | UPL_COMMIT_INACTIVATE | UPL_COMMIT_FREE_ON_EMPTY);
- upl_size -= intersection;
- }
cl.e_addr = wbp->cl_clusters[cl_index].b_addr;
}
/*
* no more room in the normal cluster mechanism
* so let's switch to the more expansive but expensive
* sparse mechanism....
- * first, we need to release the upl if we hold one
- * since pages in it may be present in the sparse cluster map (after the cluster_switch)
- * and may span 2 separate buckets there... if they do and
- * we happen to have to flush a bucket to make room and it intersects
- * this upl, a deadlock may result on page BUSY
*/
- if (upl_size)
- ubc_upl_commit_range(upl, upl_offset, upl_size,
- UPL_COMMIT_SET_DIRTY | UPL_COMMIT_INACTIVATE | UPL_COMMIT_FREE_ON_EMPTY);
-
sparse_cluster_switch(wbp, vp, newEOF, callback, callback_arg);
sparse_cluster_add(wbp, vp, &cl, newEOF, callback, callback_arg);
wbp->cl_number++;
delay_io:
- if (upl_size)
- ubc_upl_commit_range(upl, upl_offset, upl_size,
- UPL_COMMIT_SET_DIRTY | UPL_COMMIT_INACTIVATE | UPL_COMMIT_FREE_ON_EMPTY);
-
lck_mtx_unlock(&wbp->cl_lockw);
continue;
issue_io:
/*
- * we don't hold the vnode lock at this point
+ * we don't hold the lock at this point
*
- * because we had to ask for a UPL that provides currenty non-present pages, the
- * UPL has been automatically set to clear the dirty flags (both software and hardware)
- * upon committing it... this is not the behavior we want since it's possible for
- * pages currently present as part of a mapped file to be dirtied while the I/O is in flight.
- * in order to maintain some semblance of coherency with mapped writes
- * we need to drop the current upl and pick it back up with COPYOUT_FROM set
+ * we've already dropped the current upl, so pick it back up with COPYOUT_FROM set
* so that we correctly deal with a change in state of the hardware modify bit...
* we do this via cluster_push_now... by passing along the IO_SYNC flag, we force
* cluster_push_now to wait until all the I/Os have completed... cluster_push_now is also
* responsible for generating the correct sized I/O(s)
*/
- ubc_upl_commit_range(upl, 0, upl_size,
- UPL_COMMIT_SET_DIRTY | UPL_COMMIT_INACTIVATE | UPL_COMMIT_FREE_ON_EMPTY);
-
- cl.e_addr = (upl_f_offset + (off_t)upl_size) / PAGE_SIZE_64;
-
retval = cluster_push_now(vp, &cl, newEOF, flags, callback, callback_arg);
}
}
goto dont_try;
}
}
- /*
- * drop the lock while we're firing off the I/Os...
- * this is safe since I'm working off of a private sorted copy
- * of the clusters, and I'm going to re-evaluate the public
- * state after I retake the lock
- *
- * we need to drop it to avoid a lock inversion when trying to
- * grab pages into the UPL... another thread in 'write' may
- * have these pages in its UPL and be blocked trying to
- * gain the write-behind lock for this vnode
- */
- lck_mtx_unlock(&wbp->cl_lockw);
-
for (cl_index = 0; cl_index < cl_len; cl_index++) {
int flags;
struct cl_extent cl;
if ( !(push_flag & PUSH_ALL) )
break;
}
- lck_mtx_lock(&wbp->cl_lockw);
-
dont_try:
if (cl_len > cl_pushed) {
/*
wbp->cl_scdirty -= (int)(cl.e_addr - cl.b_addr);
- /*
- * drop the lock while we're firing off the I/Os...
- * this is safe since I've already updated the state
- * this lock is protecting and I'm going to re-evaluate
- * the public state after I retake the lock
- *
- * we need to drop it to avoid a lock inversion when trying to
- * grab pages into the UPL... another thread in 'write' may
- * have these pages in its UPL and be blocked trying to
- * gain the write-behind lock for this vnode
- */
- lck_mtx_unlock(&wbp->cl_lockw);
-
cluster_push_now(vp, &cl, EOF, push_flag & IO_PASSIVE, callback, callback_arg);
- lck_mtx_lock(&wbp->cl_lockw);
-
if ( !(push_flag & PUSH_ALL) )
break;
}
lcl_counter = 0;
while (jnl->old_start[i] & 0x8000000000000000LL) {
- if (lcl_counter++ > 100) {
+ if (lcl_counter++ > 1000) {
panic("jnl: check_free_space: tr starting @ 0x%llx not flushing (jnl %p).\n",
jnl->old_start[i], jnl);
}
struct timeval current_tv;
struct unsafe_fsnode *l_unsafefs = 0;
proc_t curproc = current_proc();
- pid_t current_pid = proc_pid(curproc);
retry:
microuptime(¤t_tv);
if ( !(vp->v_listflag & VLIST_RAGE) || !(vp->v_flag & VRAGE))
panic("new_vnode: vp on RAGE list not marked both VLIST_RAGE and VRAGE");
- // skip vnodes which have a dependency on this process
- // (i.e. they're vnodes in a disk image and this process
- // is diskimages-helper)
+ // if we're a dependency-capable process, skip vnodes that can
+ // cause recycling deadlocks. (i.e. this process is diskimages
+ // helper and the vnode is in a disk image).
//
- if (vp->v_mount && vp->v_mount->mnt_dependent_pid != current_pid && vp->v_mount->mnt_dependent_process != curproc) {
+ if ((curproc->p_flag & P_DEPENDENCY_CAPABLE) == 0 || vp->v_mount == NULL || vp->v_mount->mnt_dependent_process == NULL) {
break;
}
*/
walk_count = 0;
TAILQ_FOREACH(vp, &vnode_free_list, v_freelist) {
- // skip vnodes which have a dependency on this process
- // (i.e. they're vnodes in a disk image and this process
- // is diskimages-helper)
+ // if we're a dependency-capable process, skip vnodes that can
+ // cause recycling deadlocks. (i.e. this process is diskimages
+ // helper and the vnode is in a disk image)
//
- if (vp->v_mount && vp->v_mount->mnt_dependent_pid != current_pid && vp->v_mount->mnt_dependent_process != curproc) {
+ if ((curproc->p_flag & P_DEPENDENCY_CAPABLE) == 0 || vp->v_mount == NULL || vp->v_mount->mnt_dependent_process == NULL) {
break;
}
* Check for a race against unlink. We had a vnode
* but according to vnode_authorize or VNOP_OPEN it
* no longer exists.
+ *
+ * EREDRIVEOPEN: means that we were hit by the tty allocation race.
*/
- if ((error == ENOENT) && (*fmodep & O_CREAT)) {
+ if (((error == ENOENT) && (*fmodep & O_CREAT)) || (error == EREDRIVEOPEN)) {
goto again;
}
}
-9.4.0
+9.5.0
# The first line of this file contains the master version number for the kernel.
# All other instances of the kernel version in xnu are derived from this file.
__asm__ volatile("movl %%ebp, %0" : "=m" (stackptr));
/* Print backtrace - callee is internally synchronized */
- panic_i386_backtrace(stackptr, 16);
+ panic_i386_backtrace(stackptr, 16, NULL, FALSE, NULL);
/* everything should be printed now so copy to NVRAM
*/
*/
if (commit_paniclog_to_nvram) {
unsigned int bufpos;
+ uintptr_t cr0;
debug_putc(0);
* since we can subsequently halt the system.
*/
kprintf("Attempting to commit panic log to NVRAM\n");
+/* The following sequence is a workaround for:
+ * <rdar://problem/5915669> SnowLeopard10A67: AppleEFINVRAM should not invoke
+ * any routines that use floating point (MMX in this case) when saving panic
+ * logs to nvram/flash.
+ */
+ cr0 = get_cr0();
+ clear_ts();
+
pi_size = PESavePanicInfo((unsigned char *)debug_buf,
pi_size );
+ set_cr0(cr0);
/* Uncompress in-place, to permit examination of
* the panic log by debuggers.
#define DUMPFRAMES 32
#define PBT_TIMEOUT_CYCLES (5 * 1000 * 1000 * 1000ULL)
void
-panic_i386_backtrace(void *_frame, int nframes)
+panic_i386_backtrace(void *_frame, int nframes, const char *msg, boolean_t regdump, x86_saved_state_t *regs)
{
cframe_t *frame = (cframe_t *)_frame;
vm_offset_t raddrs[DUMPFRAMES];
+ vm_offset_t PC = 0;
int frame_index;
volatile uint32_t *ppbtcnt = &pbtcnt;
uint64_t bt_tsc_timeout;
PE_parse_boot_arg("keepsyms", &keepsyms);
- kdb_printf("Backtrace, "
- "Format - Frame : Return Address (4 potential args on stack) \n");
+ if (msg != NULL) {
+ kdb_printf(msg);
+ }
+
+ if ((regdump == TRUE) && (regs != NULL)) {
+ x86_saved_state32_t *ss32p = saved_state32(regs);
+
+ kdb_printf(
+ "EAX: 0x%08x, EBX: 0x%08x, ECX: 0x%08x, EDX: 0x%08x\n"
+ "CR2: 0x%08x, EBP: 0x%08x, ESI: 0x%08x, EDI: 0x%08x\n"
+ "EFL: 0x%08x, EIP: 0x%08x, CS: 0x%08x, DS: 0x%08x\n",
+ ss32p->eax,ss32p->ebx,ss32p->ecx,ss32p->edx,
+ ss32p->cr2,ss32p->ebp,ss32p->esi,ss32p->edi,
+ ss32p->efl,ss32p->eip,ss32p->cs, ss32p->ds);
+ PC = ss32p->eip;
+ }
+
+ kdb_printf("Backtrace (CPU %d), "
+ "Frame : Return Address (4 potential args on stack)\n", cpu_number());
for (frame_index = 0; frame_index < nframes; frame_index++) {
vm_offset_t curframep = (vm_offset_t) frame;
if (frame_index)
kmod_dump((vm_offset_t *)&raddrs[0], frame_index);
+ if (PC != 0)
+ kmod_dump(&PC, 1);
+
panic_display_system_configuration();
/* Release print backtrace lock, to permit other callers in the
* event of panics on multiple processors.
uint64_t maxmemtouse;
unsigned int cpus;
boolean_t legacy_mode;
+ boolean_t fidn;
postcode(I386_INIT_ENTRY);
if (!PE_parse_boot_arg("himemory_mode", &vm_himemory_mode))
vm_himemory_mode = 0;
- if (!PE_parse_boot_arg("immediate_NMI", &force_immediate_debugger_NMI))
+ if (!PE_parse_boot_argn("immediate_NMI", &fidn, sizeof (fidn)))
force_immediate_debugger_NMI = FALSE;
+ else
+ force_immediate_debugger_NMI = fidn;
/*
* At this point we check whether we are a 64-bit processor
call EXT(fn) ;\
movl %edi, %esp
-#define CCALL3(fn, arg1, arg2, arg3) \
+/*
+ * CCALL5 is used for callee functions with 3 arguments but
+ * where arg2 (a3:a2) and arg3 (a5:a4) are 64-bit values.
+ */
+#define CCALL5(fn, a1, a2, a3, a4, a5) \
movl %esp, %edi ;\
- subl $12, %esp ;\
+ subl $20, %esp ;\
andl $0xFFFFFFF0, %esp ;\
- movl arg3, 8(%esp) ;\
- movl arg2, 4(%esp) ;\
- movl arg1, 0(%esp) ;\
+ movl a5, 16(%esp) ;\
+ movl a4, 12(%esp) ;\
+ movl a3, 8(%esp) ;\
+ movl a2, 4(%esp) ;\
+ movl a1, 0(%esp) ;\
call EXT(fn) ;\
movl %edi, %esp
* Update time on user trap entry.
* Uses %eax,%ebx,%ecx,%edx,%esi,%edi.
*/
-#define TIME_TRAP_UENTRY TIMER_EVENT(USER,SYSTEM)
+#define TIME_TRAP_UENTRY TIMER_EVENT(USER,SYSTEM)
/*
* update time on user trap exit.
* Uses %eax,%ebx,%ecx,%edx,%esi,%edi.
*/
-#define TIME_TRAP_UEXIT TIMER_EVENT(SYSTEM,USER)
+#define TIME_TRAP_UEXIT TIMER_EVENT(SYSTEM,USER)
/*
* update time on interrupt entry.
popl %esp // Get back the original stack
jmp EXT(return_to_user) // Normal return, do not check asts...
2:
- CCALL3(i386_exception, $EXC_SYSCALL, $0x6000, $1)
+ CCALL5(i386_exception, $EXC_SYSCALL, $0x6000, $0, $1, $0)
// pass what would be the diag syscall
// error return - cause an exception
/* no return */
*/
Entry(lo_syscall)
+ TIME_TRAP_UENTRY
+
/*
* We can be here either for a mach, unix machdep or diag syscall,
* as indicated by the syscall class:
sti
/* Syscall class unknown */
- CCALL3(i386_exception, $(EXC_SYSCALL), %eax, $1)
+ CCALL5(i386_exception, $(EXC_SYSCALL), %eax, $0, $1, $0)
/* no return */
Entry(lo64_unix_scall)
- TIME_TRAP_UENTRY
-
movl %gs:CPU_ACTIVE_THREAD,%ecx /* get current thread */
movl ACT_TASK(%ecx),%ebx /* point to current task */
addl $1,TASK_SYSCALLS_UNIX(%ebx) /* increment call count */
Entry(lo64_mach_scall)
- TIME_TRAP_UENTRY
-
movl %gs:CPU_ACTIVE_THREAD,%ecx /* get current thread */
movl ACT_TASK(%ecx),%ebx /* point to current task */
addl $1,TASK_SYSCALLS_MACH(%ebx) /* increment call count */
Entry(lo64_mdep_scall)
- TIME_TRAP_UENTRY
-
movl %gs:CPU_ACTIVE_THREAD,%ecx /* get current thread */
movl ACT_TASK(%ecx),%ebx /* point to current task */
Entry(lo64_diag_scall)
- TIME_TRAP_UENTRY
-
movl %gs:CPU_ACTIVE_THREAD,%ecx /* get current thread */
movl ACT_TASK(%ecx),%ebx /* point to current task */
popl %esp // Get back the original stack
jmp EXT(return_to_user) // Normal return, do not check asts...
2:
- CCALL3(i386_exception, $EXC_SYSCALL, $0x6000, $1)
+ CCALL5(i386_exception, $EXC_SYSCALL, $0x6000, $0, $1, $0)
// pass what would be the diag syscall
// error return - cause an exception
/* no return */
static int NMIInterruptHandler(x86_saved_state_t *regs);
static boolean_t cpu_signal_pending(int cpu, mp_event_t event);
-static void cpu_NMI_interrupt(int cpu);
boolean_t smp_initialized = FALSE;
-boolean_t force_immediate_debugger_NMI = FALSE;
+volatile boolean_t force_immediate_debugger_NMI = FALSE;
+volatile boolean_t pmap_tlb_flush_timeout = FALSE;
decl_simple_lock_data(,mp_kdp_lock);
static int __attribute__((noinline))
NMIInterruptHandler(x86_saved_state_t *regs)
{
- boolean_t state = ml_set_interrupts_enabled(FALSE);
+ void *stackptr;
+
sync_iss_to_iks_unconditionally(regs);
+ __asm__ volatile("movl %%ebp, %0" : "=m" (stackptr));
+
+ if (pmap_tlb_flush_timeout == TRUE && current_cpu_datap()->cpu_tlb_invalid) {
+ panic_i386_backtrace(stackptr, 10, "Panic: Unresponsive processor\n", TRUE, regs);
+ panic_io_port_read();
+ mca_check_save();
+ if (pmsafe_debug)
+ pmSafeMode(¤t_cpu_datap()->lcpu, PM_SAFE_FL_SAFE);
+ for(;;) {
+ cpu_pause();
+ }
+ }
mp_kdp_wait(FALSE);
- (void) ml_set_interrupts_enabled(state);
return 1;
}
/*
* Send a true NMI via the local APIC to the specified CPU.
*/
-static void
+void
cpu_NMI_interrupt(int cpu)
{
boolean_t state;
extern int kdb_active[];
extern volatile boolean_t mp_kdp_trap;
-extern boolean_t force_immediate_debugger_NMI;
+extern volatile boolean_t force_immediate_debugger_NMI;
+extern volatile boolean_t pmap_tlb_flush_timeout;
extern void mp_kdp_enter(void);
extern void mp_kdp_exit(void);
extern int i386_active_cpus(void);
extern void i386_activate_cpu(void);
extern void i386_deactivate_cpu(void);
+extern void cpu_NMI_interrupt(int /* cpu */);
__END_DECLS
return vaddr;
}
+static inline void
+pmap_cpuset_NMIPI(cpu_set cpu_mask) {
+ unsigned int cpu, cpu_bit;
+ uint64_t deadline;
+
+ for (cpu = 0, cpu_bit = 1; cpu < real_ncpus; cpu++, cpu_bit <<= 1) {
+ if (cpu_mask & cpu_bit)
+ cpu_NMI_interrupt(cpu);
+ }
+ deadline = mach_absolute_time() + (LockTimeOut >> 2);
+ while (mach_absolute_time() < deadline)
+ cpu_pause();
+}
+
/*
* Called with pmap locked, we:
(int) pmap, cpus_to_signal, flush_self, 0, 0);
if (cpus_to_signal) {
+ cpu_set cpus_to_respond = cpus_to_signal;
+
deadline = mach_absolute_time() + LockTimeOut;
/*
* Wait for those other cpus to acknowledge
*/
- for (cpu = 0, cpu_bit = 1; cpu < real_ncpus; cpu++, cpu_bit <<= 1) {
- while ((cpus_to_signal & cpu_bit) != 0) {
- if (!cpu_datap(cpu)->cpu_running ||
- cpu_datap(cpu)->cpu_tlb_invalid == FALSE ||
- !CPU_CR3_IS_ACTIVE(cpu)) {
- cpus_to_signal &= ~cpu_bit;
- break;
- }
- if (mach_absolute_time() > deadline) {
- force_immediate_debugger_NMI = TRUE;
- panic("pmap_flush_tlbs() timeout: "
- "cpu %d failing to respond to interrupts, pmap=%p cpus_to_signal=%lx",
- cpu, pmap, cpus_to_signal);
+ while (cpus_to_respond != 0) {
+ if (mach_absolute_time() > deadline) {
+ pmap_tlb_flush_timeout = TRUE;
+ pmap_cpuset_NMIPI(cpus_to_respond);
+ panic("pmap_flush_tlbs() timeout: "
+ "cpu(s) failing to respond to interrupts, pmap=%p cpus_to_respond=0x%lx",
+ pmap, cpus_to_respond);
+ }
+
+ for (cpu = 0, cpu_bit = 1; cpu < real_ncpus; cpu++, cpu_bit <<= 1) {
+ if ((cpus_to_respond & cpu_bit) != 0) {
+ if (!cpu_datap(cpu)->cpu_running ||
+ cpu_datap(cpu)->cpu_tlb_invalid == FALSE ||
+ !CPU_CR3_IS_ACTIVE(cpu)) {
+ cpus_to_respond &= ~cpu_bit;
+ }
+ cpu_pause();
}
- cpu_pause();
+ if (cpus_to_respond == 0)
+ break;
}
- if (cpus_to_signal == 0)
- break;
}
}
if (flush_self)
flush_tlb();
-
PMAP_TRACE(PMAP_CODE(PMAP__FLUSH_TLBS) | DBG_FUNC_END,
(int) pmap, cpus_to_signal, flush_self, 0, 0);
}
/*
* Print backtrace leading to first fault:
*/
- panic_i386_backtrace((void *) my_ktss->ebp, 10);
+ panic_i386_backtrace((void *) my_ktss->ebp, 10, NULL, FALSE, NULL);
#endif
panic("Double fault at 0x%08x, thread:%p, code:0x%x, "
extern perfCallback perfASTHook;
extern perfCallback perfIntHook;
-extern void panic_i386_backtrace(void *, int);
+extern void panic_i386_backtrace(void *, int, const char *, boolean_t, x86_saved_state_t *);
#if MACH_KDP
extern boolean_t kdp_i386_trap(
unsigned int,
fill_procregioninfo(task_t task, uint64_t arg, struct proc_regioninfo_internal *pinfo, uint32_t *vnodeaddr, uint32_t *vid)
{
- vm_map_t map = task->map;
+ vm_map_t map;
vm_map_offset_t address = (vm_map_offset_t )arg;
vm_map_entry_t tmp_entry;
vm_map_entry_t entry;
vm_region_extended_info_data_t extended;
vm_region_top_info_data_t top;
-
- if (map == VM_MAP_NULL)
- return(0);
-
+ task_lock(task);
+ map = task->map;
+ if (map == VM_MAP_NULL)
+ {
+ task_unlock(task);
+ return(0);
+ }
+ vm_map_reference(map);
+ task_unlock(task);
+
vm_map_lock_read(map);
start = address;
if (!vm_map_lookup_entry(map, start, &tmp_entry)) {
if ((entry = tmp_entry->vme_next) == vm_map_to_entry(map)) {
vm_map_unlock_read(map);
+ vm_map_deallocate(map);
return(0);
}
} else {
if (fill_vnodeinfoforaddr(entry, vnodeaddr, vid) ==0) {
vm_map_unlock_read(map);
+ vm_map_deallocate(map);
return(1);
}
}
vm_map_unlock_read(map);
+ vm_map_deallocate(map);
return(1);
}
for (phys_addr = phys_start;
phys_addr < phys_end;
phys_addr += PAGE_SIZE_64) {
- pmap_page_protect(phys_addr >> 12, prot);
+ pmap_page_protect(phys_addr >> PAGE_SHIFT, prot);
}
}
return;
/* shadows on contiguous memory are not allowed */
/* we therefore can use the offset field */
- object->shadow_offset = (vm_object_offset_t)(phys_page << 12);
+ object->shadow_offset = (vm_object_offset_t)phys_page << PAGE_SHIFT;
object->size = size;
}
vm_object_unlock(object);
if(object->phys_contiguous) {
if (phys_entry) {
*phys_entry = (ppnum_t)
- (object->shadow_offset >> 12);
+ (object->shadow_offset >> PAGE_SHIFT);
}
vm_object_unlock(object);
return KERN_SUCCESS;
nxt = (vm_page_t)(mem->pageq.next);
if (!mem->fictitious) {
- mem->free = TRUE;
+ if (mem->phys_page <= vm_lopage_poolend && mem->phys_page >= vm_lopage_poolstart) {
+ mem->pageq.next = NULL;
+ vm_page_release(mem);
+ } else {
+ mem->free = TRUE;
- color = mem->phys_page & vm_color_mask;
- if (queue_empty(&free_list[color])) {
- inuse[color] = inuse_list_head;
- inuse_list_head = color;
+ color = mem->phys_page & vm_color_mask;
+ if (queue_empty(&free_list[color])) {
+ inuse[color] = inuse_list_head;
+ inuse_list_head = color;
+ }
+ queue_enter_first(&free_list[color],
+ mem,
+ vm_page_t,
+ pageq);
+ pg_count++;
}
- queue_enter_first(&free_list[color],
- mem,
- vm_page_t,
- pageq);
- pg_count++;
} else {
assert(mem->phys_page == vm_page_fictitious_addr ||
mem->phys_page == vm_page_guard_addr);