void rw_exit(krwlock_t *rwlp) { if (rwlp->rw_owner == current_thread()) { rwlp->rw_owner = NULL; lck_rw_unlock_exclusive((lck_rw_t *)&rwlp->rw_lock[0]); } else { OSDecrementAtomic((volatile SInt32 *)&rwlp->rw_readers); lck_rw_unlock_shared((lck_rw_t *)&rwlp->rw_lock[0]); } }
/* * Routine: lck_rw_unlock */ void lck_rw_unlock( lck_rw_t *lck, lck_rw_type_t lck_rw_type) { if (lck_rw_type == LCK_RW_TYPE_SHARED) lck_rw_unlock_shared(lck); else if (lck_rw_type == LCK_RW_TYPE_EXCLUSIVE) lck_rw_unlock_exclusive(lck); else panic("lck_rw_unlock(): Invalid RW lock type: %d\n", lck_rw_type); }
void rw_exit(krwlock_t *rwlp) { if (rwlp->rw_owner == current_thread()) { rwlp->rw_owner = NULL; ASSERT(rwlp->rw_readers == 0); lck_rw_unlock_exclusive((lck_rw_t *)&rwlp->rw_lock[0]); } else { atomic_dec_32((volatile uint32_t *)&rwlp->rw_readers); ASSERT(rwlp->rw_owner == 0); lck_rw_unlock_shared((lck_rw_t *)&rwlp->rw_lock[0]); } }
static u_int32_t get_tx_compl_callback_index(mbuf_tx_compl_func callback) { u_int32_t i; lck_rw_lock_shared(mbuf_tx_compl_tbl_lock); i = get_tx_compl_callback_index_locked(callback); lck_rw_unlock_shared(mbuf_tx_compl_tbl_lock); return (i); }
void m_do_tx_compl_callback(struct mbuf *m, struct ifnet *ifp) { int i; if (m == NULL) return; if ((m->m_pkthdr.pkt_flags & PKTF_TX_COMPL_TS_REQ) == 0) return; #if (DEBUG || DEVELOPMENT) if (mbuf_tx_compl_debug != 0 && ifp != NULL && (ifp->if_xflags & IFXF_TIMESTAMP_ENABLED) != 0 && (m->m_pkthdr.pkt_flags & PKTF_DRV_TS_VALID) == 0) { struct timespec now; nanouptime(&now); net_timernsec(&now, &m->m_pkthdr.pkt_timestamp); } #endif /* (DEBUG || DEVELOPMENT) */ for (i = 0; i < MAX_MBUF_TX_COMPL_FUNC; i++) { mbuf_tx_compl_func callback; if ((m->m_pkthdr.pkt_compl_callbacks & (1 << i)) == 0) continue; lck_rw_lock_shared(mbuf_tx_compl_tbl_lock); callback = mbuf_tx_compl_table[i]; lck_rw_unlock_shared(mbuf_tx_compl_tbl_lock); if (callback != NULL) { callback(m->m_pkthdr.pkt_compl_context, ifp, m->m_pkthdr.pkt_timestamp, m->m_pkthdr.drv_tx_compl_arg, m->m_pkthdr.drv_tx_compl_data, m->m_pkthdr.drv_tx_status); } } m->m_pkthdr.pkt_compl_callbacks = 0; #if (DEBUG || DEVELOPMENT) if (mbuf_tx_compl_debug != 0) { OSDecrementAtomic64(&mbuf_tx_compl_outstanding); if (ifp == NULL) atomic_add_64(&mbuf_tx_compl_aborted, 1); } #endif /* (DEBUG || DEVELOPMENT) */ }
adt_status _adt_xnu_read_unlock(ADT_LOCK lock) { adt_status ret; if(NULL == lock) { ret=ADT_INVALID_PARAM; goto end; } lck_rw_unlock_shared(lock->rw_lock); ret=ADT_OK; end: return ret; }
__private_extern__ void nunlock_9p(node_9p *np) { // DEBUG("%p", np); switch (np->lcktype) { case NODE_LCK_SHARED: lck_rw_unlock_shared(np->lck); break; case NODE_LCK_EXCLUSIVE: np->lcktype = NODE_LCK_NONE; lck_rw_unlock_exclusive(np->lck); break; case NODE_LCK_NONE: /* nothing here */ break; } }
static int vboxvfs_vnode_readdir(struct vnop_readdir_args *args) { vboxvfs_mount_t *pMount; vboxvfs_vnode_t *pVnodeData; SHFLDIRINFO *Info; uint32_t cbInfo; mount_t mp; vnode_t vnode; struct uio *uio; int rc = 0, rc2; PDEBUG("Reading directory..."); AssertReturn(args, EINVAL); AssertReturn(args->a_eofflag, EINVAL); AssertReturn(args->a_numdirent, EINVAL); uio = args->a_uio; AssertReturn(uio, EINVAL); vnode = args->a_vp; AssertReturn(vnode, EINVAL); AssertReturn(vnode_isdir(vnode), EINVAL); pVnodeData = (vboxvfs_vnode_t *)vnode_fsnode(vnode); AssertReturn(pVnodeData, EINVAL); mp = vnode_mount(vnode); AssertReturn(mp, EINVAL); pMount = (vboxvfs_mount_t *)vfs_fsprivate(mp); AssertReturn(pMount, EINVAL); lck_rw_lock_shared(pVnodeData->pLock); cbInfo = sizeof(Info) + MAXPATHLEN; Info = (SHFLDIRINFO *)RTMemAllocZ(cbInfo); if (!Info) { PDEBUG("No memory to allocate internal data"); lck_rw_unlock_shared(pVnodeData->pLock); return ENOMEM; } uint32_t index = (uint32_t)uio_offset(uio) / (uint32_t)sizeof(struct dirent); uint32_t cFiles = 0; PDEBUG("Exploring VBoxVFS directory (%s), handle (0x%.8X), offset (0x%X), count (%d)", (char *)pVnodeData->pPath->String.utf8, (int)pVnodeData->pHandle, index, uio_iovcnt(uio)); /* Currently, there is a problem when VbglR0SfDirInfo() is not able to * continue retrieve directory content if the same VBoxVFS handle is used. * This macro forces to use a new handle in readdir() callback. If enabled, * the original handle (obtained in open() callback is ignored). */ SHFLHANDLE Handle; rc = vboxvfs_open_internal(pMount, pVnodeData->pPath, SHFL_CF_DIRECTORY | SHFL_CF_ACCESS_READ | SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW, &Handle); if (rc != 0) { PDEBUG("Unable to open dir: %d", rc); RTMemFree(Info); lck_rw_unlock_shared(pVnodeData->pLock); return rc; } #if 0 rc = VbglR0SfDirInfo(&g_vboxSFClient, &pMount->pMap, Handle, 0, 0, index, &cbInfo, (PSHFLDIRINFO)Info, &cFiles); #else SHFLSTRING *pMask = vboxvfs_construct_shflstring("*", strlen("*")); if (pMask) { for (uint32_t cSkip = 0; (cSkip < index + 1) && (rc == VINF_SUCCESS); cSkip++) { //rc = VbglR0SfDirInfo(&g_vboxSFClient, &pMount->pMap, Handle, 0 /* pMask */, 0 /* SHFL_LIST_RETURN_ONE */, 0, &cbInfo, (PSHFLDIRINFO)Info, &cFiles); uint32_t cbReturned = cbInfo; //rc = VbglR0SfDirInfo(&g_vboxSFClient, &pMount->pMap, Handle, pMask, SHFL_LIST_RETURN_ONE, 0, &cbReturned, (PSHFLDIRINFO)Info, &cFiles); rc = VbglR0SfDirInfo(&g_vboxSFClient, &pMount->pMap, Handle, 0, SHFL_LIST_RETURN_ONE, 0, &cbReturned, (PSHFLDIRINFO)Info, &cFiles); } PDEBUG("read %d files", cFiles); RTMemFree(pMask); } else { PDEBUG("Can't alloc mask"); rc = ENOMEM; } #endif rc2 = vboxvfs_close_internal(pMount, Handle); if (rc2 != 0) { PDEBUG("Unable to close directory: %s: %d", pVnodeData->pPath->String.utf8, rc2); } switch (rc) { case VINF_SUCCESS: { rc = vboxvfs_vnode_readdir_copy_data((ino_t)(index + 1), Info, uio, args->a_numdirent); break; } case VERR_NO_MORE_FILES: { PDEBUG("No more entries in directory"); *(args->a_eofflag) = 1; break; } default: { PDEBUG("VbglR0SfDirInfo() for item #%d has failed: %d", (int)index, (int)rc); rc = EINVAL; break; } } RTMemFree(Info); lck_rw_unlock_shared(pVnodeData->pLock); return rc; }
static int vboxvfs_vnode_getattr(struct vnop_getattr_args *args) { vboxvfs_mount_t *pMount; struct vnode_attr *vnode_args; vboxvfs_vnode_t *pVnodeData; struct timespec timespec; SHFLFSOBJINFO Info; mount_t mp; vnode_t vnode; int rc; PDEBUG("Getting vnode attribute..."); AssertReturn(args, EINVAL); vnode = args->a_vp; AssertReturn(vnode, EINVAL); vnode_args = args->a_vap; AssertReturn(vnode_args, EINVAL); mp = vnode_mount(vnode); AssertReturn(mp, EINVAL); pMount = (vboxvfs_mount_t *)vfs_fsprivate(mp); AssertReturn(pMount, EINVAL); pVnodeData = (vboxvfs_vnode_t *)vnode_fsnode(vnode); AssertReturn(pVnodeData, EINVAL); lck_rw_lock_shared(pVnodeData->pLock); rc = vboxvfs_get_info_internal(mp, pVnodeData->pPath, &Info); if (rc == 0) { /* Set timestamps */ RTTimeSpecGetTimespec(&Info.BirthTime, ×pec); VATTR_RETURN(vnode_args, va_create_time, timespec); RTTimeSpecGetTimespec(&Info.AccessTime, ×pec); VATTR_RETURN(vnode_args, va_access_time, timespec); RTTimeSpecGetTimespec(&Info.ModificationTime, ×pec); VATTR_RETURN(vnode_args, va_modify_time, timespec); RTTimeSpecGetTimespec(&Info.ChangeTime, ×pec); VATTR_RETURN(vnode_args, va_change_time, timespec); VATTR_CLEAR_ACTIVE(vnode_args, va_backup_time); /* Set owner info. */ VATTR_RETURN(vnode_args, va_uid, pMount->owner); VATTR_CLEAR_ACTIVE(vnode_args, va_gid); /* Access mode and flags */ VATTR_RETURN(vnode_args, va_mode, vboxvfs_h2g_mode_inernal(Info.Attr.fMode)); VATTR_RETURN(vnode_args, va_flags, Info.Attr.u.Unix.fFlags); /* The current generation number (0 if this information is not available) */ VATTR_RETURN(vnode_args, va_gen, Info.Attr.u.Unix.GenerationId); VATTR_RETURN(vnode_args, va_rdev, 0); VATTR_RETURN(vnode_args, va_nlink, 2); VATTR_RETURN(vnode_args, va_data_size, sizeof(struct dirent)); /* Size of data returned per each readdir() request */ /* Hope, when it overflows nothing catastrophical will heppen! If we will not assign * a uniq va_fileid to each vnode, `ls`, 'find' (and simmilar tools that uses fts_read() calls) will think that * each sub-directory is self-cycled. */ VATTR_RETURN(vnode_args, va_fileid, (pMount->cFileIdCounter++)); /* Not supported */ VATTR_CLEAR_ACTIVE(vnode_args, va_linkid); VATTR_CLEAR_ACTIVE(vnode_args, va_parentid); VATTR_CLEAR_ACTIVE(vnode_args, va_fsid); VATTR_CLEAR_ACTIVE(vnode_args, va_filerev); /* Not present on 10.6 */ //VATTR_CLEAR_ACTIVE(vnode_args, va_addedtime); /* todo: take care about va_encoding (file name encoding) */ VATTR_CLEAR_ACTIVE(vnode_args, va_encoding); /* todo: take care about: va_acl */ VATTR_CLEAR_ACTIVE(vnode_args, va_acl); VATTR_CLEAR_ACTIVE(vnode_args, va_name); VATTR_CLEAR_ACTIVE(vnode_args, va_uuuid); VATTR_CLEAR_ACTIVE(vnode_args, va_guuid); VATTR_CLEAR_ACTIVE(vnode_args, va_total_size); VATTR_CLEAR_ACTIVE(vnode_args, va_total_alloc); VATTR_CLEAR_ACTIVE(vnode_args, va_data_alloc); VATTR_CLEAR_ACTIVE(vnode_args, va_iosize); VATTR_CLEAR_ACTIVE(vnode_args, va_nchildren); VATTR_CLEAR_ACTIVE(vnode_args, va_dirlinkcount); } else { PDEBUG("getattr: unable to get VBoxVFS object info"); } lck_rw_unlock_shared(pVnodeData->pLock); return rc; }
kern_return_t dtrace_user_probe(arm_saved_state_t *regs, unsigned int instr) { /* * FIXME * * The only call path into this method is always a user trap. * We don't need to test for user trap, but should assert it. */ lck_rw_t *rwp; struct proc *p = current_proc(); uthread_t uthread = (uthread_t)get_bsdthread_info(current_thread()); kauth_cred_uthread_update(uthread, p); if (((regs->cpsr & PSR_TF) && ((uint16_t) instr) == FASTTRAP_THUMB_RET_INSTR) || ((uint32_t) instr == FASTTRAP_ARM_RET_INSTR)) { uint8_t step = uthread->t_dtrace_step; uint8_t ret = uthread->t_dtrace_ret; user_addr_t npc = uthread->t_dtrace_npc; if (uthread->t_dtrace_ast) { printf("dtrace_user_probe() should be calling aston()\n"); // aston(thread); // uthread->t_sig_check = 1; } /* * Clear all user tracing flags. */ uthread->t_dtrace_ft = 0; /* * If we weren't expecting to take a return probe trap, kill * the process as though it had just executed an unassigned * trap instruction. */ if (step == 0) { /* * APPLE NOTE: We're returning KERN_FAILURE, which causes * the generic signal handling code to take over, which will effectively * deliver a EXC_BAD_INSTRUCTION to the user process. */ return KERN_FAILURE; } /* * If we hit this trap unrelated to a return probe, we're * just here to reset the AST flag since we deferred a signal * until after we logically single-stepped the instruction we * copied out. */ if (ret == 0) { regs->pc = npc; return KERN_SUCCESS; } /* * We need to wait until after we've called the * dtrace_return_probe_ptr function pointer to step the pc. */ rwp = &CPU->cpu_ft_lock; lck_rw_lock_shared(rwp); if (dtrace_return_probe_ptr != NULL) (void) (*dtrace_return_probe_ptr)(regs); lck_rw_unlock_shared(rwp); regs->pc = npc; return KERN_SUCCESS; } else { rwp = &CPU->cpu_ft_lock; /* * The DTrace fasttrap provider uses a trap, * FASTTRAP_{ARM,THUMB}_INSTR. We let * DTrace take the first crack at handling * this trap; if it's not a probe that DTrace knows about, * we call into the trap() routine to handle it like a * breakpoint placed by a conventional debugger. */ /* * APPLE NOTE: I believe the purpose of the reader/writers lock * is thus: There are times which dtrace needs to prevent calling * dtrace_pid_probe_ptr(). Sun's original impl grabbed a plain * mutex here. However, that serialized all probe calls, and * destroyed MP behavior. So now they use a RW lock, with probes * as readers, and the top level synchronization as a writer. */ lck_rw_lock_shared(rwp); if (dtrace_pid_probe_ptr != NULL && (*dtrace_pid_probe_ptr)(regs) == 0) { lck_rw_unlock_shared(rwp); return KERN_SUCCESS; } lck_rw_unlock_shared(rwp); /* * If the instruction that caused the breakpoint trap doesn't * look like our trap anymore, it may be that this tracepoint * was removed just after the user thread executed it. In * that case, return to user land to retry the instuction. * * Note that the PC points to the instruction that caused the fault. */ if (regs->cpsr & PSR_TF) { uint16_t instr_check; if (fuword16(regs->pc, &instr_check) == 0 && instr_check != FASTTRAP_THUMB_INSTR) { return KERN_SUCCESS; } } else { uint32_t instr_check; if (fuword32(regs->pc, &instr_check) == 0 && instr_check != FASTTRAP_ARM_INSTR) { return KERN_SUCCESS; } } } return KERN_FAILURE; }
/** * ntfs_pagein - read a range of pages into memory * @ni: ntfs inode whose data to read into the page range * @attr_ofs: byte offset in the inode at which to start * @size: number of bytes to read from the inode * @upl: page list describing destination page range * @upl_ofs: byte offset into page list at which to start * @flags: flags further describing the pagein request * * Read @size bytes from the ntfs inode @ni, starting at byte offset @attr_ofs * into the inode, into the range of pages specified by the page list @upl, * starting at byte offset @upl_ofs into the page list. * * The @flags further describe the pagein request. The following pagein flags * are currently defined in OSX kernel: * UPL_IOSYNC - Perform synchronous i/o. * UPL_NOCOMMIT - Do not commit/abort the page range. * UPL_NORDAHEAD - Do not perform any speculative read-ahead. * IO_PASSIVE - This is background i/o so do not throttle other i/o. * * Inside the ntfs driver we have the need to perform pageins whilst the inode * is locked for writing (@ni->lock) thus we cheat and set UPL_NESTED_PAGEOUT * in @flags when this is the case. We make sure to clear it in @flags before * calling into the cluster layer so we do not accidentally cause confusion. * * For encrypted attributes we abort for now as we do not support them yet. * * For non-resident, non-compressed attributes we use cluster_pagein_ext() * which deals with both normal and multi sector transfer protected attributes. * * For resident attributes and non-resident, compressed attributes we read the * data ourselves by mapping the page list, and in the resident case, mapping * the mft record, looking up the attribute in it, and copying the requested * data from the mapped attribute into the page list, then unmapping the mft * record, whilst for non-resident, compressed attributes, we get the raw inode * and use it with ntfs_read_compressed() to read and decompress the data into * our mapped page list. We then unmap the page list and finally, if * UPL_NOCOMMIT is not specified, we commit (success) or abort (error) the page * range. * * Return 0 on success and errno on error. * * Note the pages in the page list are marked busy on entry and the busy bit is * cleared when we commit the page range. Thus it is perfectly safe for us to * fill the pages with encrypted or mst protected data and to decrypt or mst * deprotect in place before committing the page range. * * Adapted from cluster_pagein_ext(). * * Locking: - Caller must hold an iocount reference on the vnode of @ni. * - Caller must not hold @ni->lock or if it is held it must be for * reading unless UPL_NESTED_PAGEOUT is set in @flags in which case * the caller must hold @ni->lock for reading or writing. */ int ntfs_pagein(ntfs_inode *ni, s64 attr_ofs, unsigned size, upl_t upl, upl_offset_t upl_ofs, int flags) { s64 attr_size; u8 *kaddr; kern_return_t kerr; unsigned to_read; int err; BOOL locked = FALSE; ntfs_debug("Entering for mft_no 0x%llx, offset 0x%llx, size 0x%x, " "pagein flags 0x%x, page list offset 0x%llx.", (unsigned long long)ni->mft_no, (unsigned long long)attr_ofs, size, flags, (unsigned long long)upl_ofs); /* * If the caller did not specify any i/o, then we are done. We cannot * issue an abort because we do not have a upl or we do not know its * size. */ if (!upl) { ntfs_error(ni->vol->mp, "NULL page list passed in (error " "EINVAL)."); return EINVAL; } if (S_ISDIR(ni->mode)) { ntfs_error(ni->vol->mp, "Called for directory vnode."); err = EISDIR; goto err; } /* * Protect against changes in initialized_size and thus against * truncation also unless UPL_NESTED_PAGEOUT is set in which case the * caller has already taken @ni->lock for exclusive access. We simply * leave @locked to be FALSE in this case so we do not try to drop the * lock later on. * * If UPL_NESTED_PAGEOUT is set we clear it in @flags to ensure we do * not cause confusion in the cluster layer or the VM. */ if (flags & UPL_NESTED_PAGEOUT) flags &= ~UPL_NESTED_PAGEOUT; else { locked = TRUE; lck_rw_lock_shared(&ni->lock); } /* Do not allow messing with the inode once it has been deleted. */ if (NInoDeleted(ni)) { /* Remove the inode from the name cache. */ cache_purge(ni->vn); err = ENOENT; goto err; } retry_pagein: /* * We guarantee that the size in the ubc will be smaller or equal to * the size in the ntfs inode thus no need to check @ni->data_size. */ attr_size = ubc_getsize(ni->vn); /* * Only $DATA attributes can be encrypted/compressed. Index root can * have the flags set but this means to create compressed/encrypted * files, not that the attribute is compressed/encrypted. Note we need * to check for AT_INDEX_ALLOCATION since this is the type of directory * index inodes. */ if (ni->type != AT_INDEX_ALLOCATION) { /* TODO: Deny access to encrypted attributes, just like NT4. */ if (NInoEncrypted(ni)) { if (ni->type != AT_DATA) panic("%s(): Encrypted non-data attribute.\n", __FUNCTION__); ntfs_warning(ni->vol->mp, "Denying access to " "encrypted attribute (EACCES)."); err = EACCES; goto err; } /* Compressed data streams need special handling. */ if (NInoNonResident(ni) && NInoCompressed(ni) && !NInoRaw(ni)) { if (ni->type != AT_DATA) panic("%s(): Compressed non-data attribute.\n", __FUNCTION__); goto compressed; } } /* NInoNonResident() == NInoIndexAllocPresent() */ if (NInoNonResident(ni)) { int (*callback)(buf_t, void *); callback = NULL; if (NInoMstProtected(ni) || NInoEncrypted(ni)) callback = ntfs_cluster_iodone; /* Non-resident, possibly mst protected, attribute. */ err = cluster_pagein_ext(ni->vn, upl, upl_ofs, attr_ofs, size, attr_size, flags, callback, NULL); if (!err) ntfs_debug("Done (cluster_pagein_ext())."); else ntfs_error(ni->vol->mp, "Failed (cluster_pagein_ext(), " "error %d).", err); if (locked) lck_rw_unlock_shared(&ni->lock); return err; } compressed: /* * The attribute is resident and/or compressed. * * Cannot pagein from a negative offset or if we are starting beyond * the end of the attribute or if the attribute offset is not page * aligned or the size requested is not a multiple of PAGE_SIZE. */ if (attr_ofs < 0 || attr_ofs >= attr_size || attr_ofs & PAGE_MASK_64 || size & PAGE_MASK || upl_ofs & PAGE_MASK) { err = EINVAL; goto err; } to_read = size; attr_size -= attr_ofs; if (to_read > attr_size) to_read = attr_size; /* * We do not need @attr_size any more so reuse it to hold the number of * bytes available in the attribute starting at offset @attr_ofs up to * a maximum of the requested number of bytes rounded up to a multiple * of the system page size. */ attr_size = (to_read + PAGE_MASK) & ~PAGE_MASK; /* Abort any pages outside the end of the attribute. */ if (size > attr_size && !(flags & UPL_NOCOMMIT)) { ubc_upl_abort_range(upl, upl_ofs + attr_size, size - attr_size, UPL_ABORT_FREE_ON_EMPTY | UPL_ABORT_ERROR); /* Update @size. */ size = attr_size; } /* To access the page list contents, we need to map the page list. */ kerr = ubc_upl_map(upl, (vm_offset_t*)&kaddr); if (kerr != KERN_SUCCESS) { ntfs_error(ni->vol->mp, "ubc_upl_map() failed (error %d).", (int)kerr); err = EIO; goto err; } if (!NInoNonResident(ni)) { /* * Read the data from the resident attribute into the page * list. */ err = ntfs_resident_attr_read(ni, attr_ofs, size, kaddr + upl_ofs); if (err && err != EAGAIN) ntfs_error(ni->vol->mp, "ntfs_resident_attr_read() " "failed (error %d).", err); } else { ntfs_inode *raw_ni; int ioflags; /* * Get the raw inode. We take the inode lock shared to protect * against concurrent writers as the compressed data is invalid * whilst a write is in progress. */ err = ntfs_raw_inode_get(ni, LCK_RW_TYPE_SHARED, &raw_ni); if (err) ntfs_error(ni->vol->mp, "Failed to get raw inode " "(error %d).", err); else { if (!NInoRaw(raw_ni)) panic("%s(): Requested raw inode but got " "non-raw one.\n", __FUNCTION__); ioflags = 0; if (vnode_isnocache(ni->vn) || vnode_isnocache(raw_ni->vn)) ioflags |= IO_NOCACHE; if (vnode_isnoreadahead(ni->vn) || vnode_isnoreadahead(raw_ni->vn)) ioflags |= IO_RAOFF; err = ntfs_read_compressed(ni, raw_ni, attr_ofs, size, kaddr + upl_ofs, NULL, ioflags); if (err) ntfs_error(ni->vol->mp, "ntfs_read_compressed() " "failed (error %d).", err); lck_rw_unlock_shared(&raw_ni->lock); (void)vnode_put(raw_ni->vn); } } kerr = ubc_upl_unmap(upl); if (kerr != KERN_SUCCESS) { ntfs_error(ni->vol->mp, "ubc_upl_unmap() failed (error %d).", (int)kerr); if (!err) err = EIO; } if (!err) { if (!(flags & UPL_NOCOMMIT)) { /* Commit the page range we brought up to date. */ ubc_upl_commit_range(upl, upl_ofs, size, UPL_COMMIT_FREE_ON_EMPTY); } ntfs_debug("Done (%s).", !NInoNonResident(ni) ? "ntfs_resident_attr_read()" : "ntfs_read_compressed()"); } else /* if (err) */ { /* * If the attribute was converted to non-resident under our * nose, retry the pagein. * * TODO: This may no longer be possible to happen now that we * lock against changes in initialized size and thus * truncation... Revisit this issue when the write code has * been written and remove the check + goto if appropriate. */ if (err == EAGAIN) goto retry_pagein; err: if (!(flags & UPL_NOCOMMIT)) { int upl_flags = UPL_ABORT_FREE_ON_EMPTY; if (err != ENOMEM) upl_flags |= UPL_ABORT_ERROR; ubc_upl_abort_range(upl, upl_ofs, size, upl_flags); } ntfs_error(ni->vol->mp, "Failed (error %d).", err); } if (locked) lck_rw_unlock_shared(&ni->lock); return err; }
kern_return_t dtrace_user_probe(x86_saved_state_t *regs) { x86_saved_state64_t *regs64; x86_saved_state32_t *regs32; int trapno; /* * FIXME! * * The only call path into this method is always a user trap. * We don't need to test for user trap, but should assert it. */ boolean_t user_mode = TRUE; if (is_saved_state64(regs) == TRUE) { regs64 = saved_state64(regs); regs32 = NULL; trapno = regs64->isf.trapno; user_mode = TRUE; // By default, because xnu is 32 bit only } else { regs64 = NULL; regs32 = saved_state32(regs); if (regs32->cs & 0x03) user_mode = TRUE; trapno = regs32->trapno; } lck_rw_t *rwp; struct proc *p = current_proc(); uthread_t uthread = (uthread_t)get_bsdthread_info(current_thread()); if (user_mode /*|| (rp->r_ps & PS_VM)*/) { /* * DTrace accesses t_cred in probe context. t_cred * must always be either NULL, or point to a valid, * allocated cred structure. */ kauth_cred_uthread_update(uthread, p); } if (trapno == T_DTRACE_RET) { uint8_t step = uthread->t_dtrace_step; uint8_t ret = uthread->t_dtrace_ret; user_addr_t npc = uthread->t_dtrace_npc; if (uthread->t_dtrace_ast) { printf("dtrace_user_probe() should be calling aston()\n"); // aston(uthread); // uthread->t_sig_check = 1; } /* * Clear all user tracing flags. */ uthread->t_dtrace_ft = 0; /* * If we weren't expecting to take a return probe trap, kill * the process as though it had just executed an unassigned * trap instruction. */ if (step == 0) { /* * APPLE NOTE: We're returning KERN_FAILURE, which causes * the generic signal handling code to take over, which will effectively * deliver a EXC_BAD_INSTRUCTION to the user process. */ return KERN_FAILURE; } /* * If we hit this trap unrelated to a return probe, we're * just here to reset the AST flag since we deferred a signal * until after we logically single-stepped the instruction we * copied out. */ if (ret == 0) { if (regs64) { regs64->isf.rip = npc; } else { regs32->eip = npc; } return KERN_SUCCESS; } /* * We need to wait until after we've called the * dtrace_return_probe_ptr function pointer to set %pc. */ rwp = &CPU->cpu_ft_lock; lck_rw_lock_shared(rwp); if (dtrace_return_probe_ptr != NULL) (void) (*dtrace_return_probe_ptr)(regs); lck_rw_unlock_shared(rwp); if (regs64) { regs64->isf.rip = npc; } else { regs32->eip = npc; } return KERN_SUCCESS; } else if (trapno == T_INT3) { uint8_t instr; rwp = &CPU->cpu_ft_lock; /* * The DTrace fasttrap provider uses the breakpoint trap * (int 3). We let DTrace take the first crack at handling * this trap; if it's not a probe that DTrace knowns about, * we call into the trap() routine to handle it like a * breakpoint placed by a conventional debugger. */ /* * APPLE NOTE: I believe the purpose of the reader/writers lock * is thus: There are times which dtrace needs to prevent calling * dtrace_pid_probe_ptr(). Sun's original impl grabbed a plain * mutex here. However, that serialized all probe calls, and * destroyed MP behavior. So now they use a RW lock, with probes * as readers, and the top level synchronization as a writer. */ lck_rw_lock_shared(rwp); if (dtrace_pid_probe_ptr != NULL && (*dtrace_pid_probe_ptr)(regs) == 0) { lck_rw_unlock_shared(rwp); return KERN_SUCCESS; } lck_rw_unlock_shared(rwp); /* * If the instruction that caused the breakpoint trap doesn't * look like an int 3 anymore, it may be that this tracepoint * was removed just after the user thread executed it. In * that case, return to user land to retry the instuction. */ user_addr_t pc = (regs64) ? regs64->isf.rip : (user_addr_t)regs32->eip; if (fuword8(pc - 1, &instr) == 0 && instr != FASTTRAP_INSTR) { if (regs64) { regs64->isf.rip--; } else { regs32->eip--; } return KERN_SUCCESS; } } return KERN_FAILURE; }
struct lpxpcb * Lpx_PCB_lookup( struct lpx_addr *faddr, // peer addr:port struct lpx_addr *laddr, // local addr:port int wildp, struct lpxpcb *head ) { register struct lpxpcb *lpxp, *match = NULL; int matchwild = 3, wildcard = 0; /* matching cost */ u_short fport; u_short lport; // DEBUG_PRINT(DEBUG_MASK_PCB_TRACE, ("Lpx_PCB_lookup\n")); /* Check arguments */ if (NULL == faddr || NULL == head) { return (NULL); } fport = faddr->x_port; lport = laddr->x_port; // DEBUG_PRINT(DEBUG_MASK_PCB_INFO, ("PCBLU>> lpxpcb@(%lx):lpx_next@(%lx) %02x:%02x:%02x:%02x:%02x:%02x faddr->xport = %d, lport = %d wildp = %d\n",&lpxpcb, lpxpcb.lpxp_next, faddr->x_node[0],faddr->x_node[1],faddr->x_node[2],faddr->x_node[3],faddr->x_node[4],faddr->x_node[5], faddr->x_port, lport, wildp)); lck_rw_lock_shared(head->lpxp_list_rw); for (lpxp = (head)->lpxp_next; lpxp != (head); lpxp = lpxp->lpxp_next) { // DEBUG_PRINT(DEBUG_MASK_PCB_INFO, ("PCBLU>> lpxp@(%lx) %02x:%02x:%02x:%02x:%02x:%02x lpxp_lport = %d, lpxp_fport = %d \n", lpxp, lpxp->lpxp_faddr.x_node[0], lpxp->lpxp_faddr.x_node[1], lpxp->lpxp_faddr.x_node[2], lpxp->lpxp_faddr.x_node[3], lpxp->lpxp_faddr.x_node[4], lpxp->lpxp_faddr.x_node[5], lpxp->lpxp_lport, lpxp->lpxp_fport)); if (lpxp->lpxp_lport == lport) { /* at least local port number should match */ wildcard = 0; if (lpx_nullhost(lpxp->lpxp_faddr)) { /* no peer address registered : INADDR_ANY */ if (!lpx_nullhost(*faddr)) { if (lpx_hosteq(lpxp->lpxp_laddr, *laddr)) { // DEBUG_PRINT(DEBUG_MASK_PCB_INFO, ("Maybe broadcast packet.PCBLU>> lpxp@(%lx) %02x:%02x:%02x:%02x:%02x:%02x lpxp_lport = %d, lpxp_fport = %d \n", lpxp, lpxp->lpxp_laddr.x_node[0], lpxp->lpxp_laddr.x_node[1], lpxp->lpxp_laddr.x_node[2], lpxp->lpxp_laddr.x_node[3], lpxp->lpxp_laddr.x_node[4], lpxp->lpxp_laddr.x_node[5], lpxp->lpxp_lport, lpxp->lpxp_fport)); } else { wildcard++; } } } else { /* peer address is in the DB */ if (lpx_nullhost(*faddr)) { wildcard++; } else { if (!lpx_hosteq(lpxp->lpxp_faddr, *faddr)) {/* peer address don't match */ continue; } if (lpxp->lpxp_fport != fport) { if (lpxp->lpxp_fport != 0) { /* peer port number don't match */ continue; } else { wildcard++; } } } } // DEBUG_PRINT(DEBUG_MASK_PCB_INFO, ("PCBLU>> matchwild = %d, wildcard = %d\n",matchwild, wildcard)); if (wildcard && (wildp == 0)) { /* if wildcard match is allowed */ continue; } if (wildcard < matchwild) { match = lpxp; matchwild = wildcard; if (wildcard == 0) { /* exact match : all done */ break; } } } /* if (lpxp->lpxp_lport == lport) */ } /* for (lpxp = ...) ... */ lck_rw_unlock_shared(head->lpxp_list_rw); //DEBUG_PRINT(DEBUG_MASK_PCB_INFO, ("PCBLU>> match@(%lx) matchwild = %d, wildcard = %d\n", match, matchwild, wildcard)); if (match) { // DEBUG_PRINT(DEBUG_MASK_PCB_INFO, ("PCBLU>> match@(%lx) matchwild = %d, wildcard = %d\n", match, matchwild, wildcard)); } return (match); }