int readFile(char *file, uint8_t *buffer, off_t offset, user_size_t size) { int res = EIO; vfs_context_t vfsContext = vfs_context_create(NULL); if (vfsContext == NULL) { return EIO; } vnode_t fileVnode = NULLVP; if (vnode_lookup(file, 0, &fileVnode, vfsContext) == 0) { uio_t uio = uio_create(1, offset, UIO_SYSSPACE, UIO_READ); if (uio == NULL) goto exit; if (uio_addiov(uio, CAST_USER_ADDR_T(buffer), size)) goto exit; if (VNOP_READ(fileVnode, uio, 0, vfsContext)) goto exit; if (uio_resid(uio)) goto exit; res = 0; } else { vfs_context_rele(vfsContext); return ENOENT; } exit: vnode_put(fileVnode); vfs_context_rele(vfsContext); return res; }
int zfs_vn_rdwr(enum uio_rw rw, struct vnode *vp, caddr_t base, ssize_t len, offset_t offset, enum uio_seg seg, int ioflag, rlim64_t ulimit, cred_t *cr, ssize_t *residp) { uio_t *auio; int spacetype; int error=0; vfs_context_t vctx; spacetype = UIO_SEG_IS_USER_SPACE(seg) ? UIO_USERSPACE32 : UIO_SYSSPACE; vctx = vfs_context_create((vfs_context_t)0); auio = uio_create(1, 0, spacetype, rw); uio_reset(auio, offset, spacetype, rw); uio_addiov(auio, (uint64_t)(uintptr_t)base, len); if (rw == UIO_READ) { error = VNOP_READ(vp, auio, ioflag, vctx); } else { error = VNOP_WRITE(vp, auio, ioflag, vctx); } if (residp) { *residp = uio_resid(auio); } else { if (uio_resid(auio) && error == 0) error = EIO; } uio_free(auio); vfs_context_rele(vctx); return (error); }
bool VNodeDiskDeviceClass::setupVNode() { int vapError = -1; struct vnode_attr vap; if (m_vnode != NULL) return true; vfs_context_t vfsContext = vfs_context_create((vfs_context_t) 0); int vnodeError = vnode_open(m_filePath->getCStringNoCopy(), (FREAD | FWRITE), 0, 0, &m_vnode, vfsContext); if (vnodeError || m_vnode == NULL) { IOLog("Error when opening file %s: error %d\n", m_filePath->getCStringNoCopy(), vnodeError); goto failure; } if (!vnode_isreg(m_vnode)) { IOLog("Error when opening file %s: not a regular file\n", m_filePath->getCStringNoCopy()); vnode_close(m_vnode, (FREAD | FWRITE), vfsContext); goto failure; } VATTR_INIT(&vap); VATTR_WANTED(&vap, va_data_size); vapError = vnode_getattr(m_vnode, &vap, vfsContext); if (vapError) { IOLog("Error when retrieving vnode's attributes with error code %d\n", vapError); goto failure; } if (vap.va_data_size < m_blockSize * m_blockNum) { IOLog("Error file %s is too small, actual size is %llu\n", m_filePath->getCStringNoCopy(), vap.va_data_size); goto failure; } vfs_context_rele(vfsContext); return true; failure: vfs_context_rele(vfsContext); return false; }
int kern_file_close(struct cfs_kern_file *fp) { vnode_close(fp->f_vp, fp->f_flags, fp->f_ctxt); vfs_context_rele(fp->f_ctxt); _FREE(fp, M_TEMP); return 0; }
void VNodeDiskDeviceClass::closeVNode() { if (m_vnode != NULL) { IOLog("Closing the file node\n"); vfs_context_t vfsContext = vfs_context_create((vfs_context_t) 0); vnode_close(m_vnode, 0, vfsContext); vfs_context_rele(vfsContext); m_vnode = NULL; } }
int VOP_FSYNC(struct vnode *vp, int flags, void* unused, void *uused2) { vfs_context_t vctx; int error; vctx = vfs_context_create((vfs_context_t)0); error = VNOP_FSYNC(vp, (flags == FSYNC), vctx); (void) vfs_context_rele(vctx); return (error); }
int VOP_CLOSE(struct vnode *vp, int flag, int count, offset_t off, void *cr, void *k) { vfs_context_t vctx; int error; vctx = vfs_context_create((vfs_context_t)0); error = vnode_close(vp, flag & FWRITE, vctx); (void) vfs_context_rele(vctx); return (error); }
int vn_rename(char *from, char *to, enum uio_seg seg) { vfs_context_t vctx; int error; vctx = vfs_context_create((vfs_context_t)0); error = vnode_rename(from, to, 0, vctx); (void) vfs_context_rele(vctx); return (error); }
void kern_close_file_for_direct_io(struct kern_direct_file_io_ref_t * ref, off_t write_offset, caddr_t addr, vm_size_t write_length, off_t discard_offset, off_t discard_end) { int error; kprintf("kern_close_file_for_direct_io\n"); if (!ref) return; if (ref->vp) { int (*do_ioctl)(void * p1, void * p2, u_long theIoctl, caddr_t result); void * p1; void * p2; if (ref->vp->v_type == VREG) { p1 = &ref->device; p2 = kernproc; do_ioctl = &file_ioctl; } else { /* Partition. */ p1 = ref->vp; p2 = ref->ctx; do_ioctl = &device_ioctl; } (void) do_ioctl(p1, p2, DKIOCUNLOCKPHYSICALEXTENTS, NULL); if (addr && write_length) { (void) kern_write_file(ref, write_offset, addr, write_length); } if (discard_offset && discard_end && !ref->pinned) { (void) kern_ioctl_file_extents(ref, DKIOCUNMAP, discard_offset, discard_end); } error = vnode_close(ref->vp, FWRITE, ref->ctx); ref->vp = NULLVP; kprintf("vnode_close(%d)\n", error); } vfs_context_rele(ref->ctx); ref->ctx = NULL; kfree(ref, sizeof(struct kern_direct_file_io_ref_t)); }
int VOP_GETATTR(struct vnode *vp, vattr_t *vap, int flags, void *x3, void *x4) { vfs_context_t vctx; int error; //vap->va_size = 134217728; //return 0; // panic("take this"); //printf("VOP_GETATTR(%p, %p, %d)\n", vp, vap, flags); vctx = vfs_context_create((vfs_context_t)0); error= vnode_getattr(vp, vap, vctx); (void) vfs_context_rele(vctx); return error; }
void shutdown_osi(void) { AFS_STATCNT(shutdown_osi); #ifdef AFS_DARWIN80_ENV if (afs_osi_ctxtp_initialized && afs_osi_ctxtp) { vfs_context_rele(afs_osi_ctxtp); afs_osi_ctxtp = NULL; afs_osi_ctxtp_initialized = 0; } shutdown_osisleep(); #endif if (afs_cold_shutdown) { LOCK_INIT(&afs_ftf, "afs_ftf"); } }
int vn_remove(char *fnamep, enum uio_seg seg, enum rm dirflag) { vfs_context_t vctx; enum vtype type; int error; type = dirflag == RMDIRECTORY ? VDIR : VREG; vctx = vfs_context_create((vfs_context_t)0); error = vnode_remove(fnamep, 0, type, vctx); (void) vfs_context_rele(vctx); return (error); }
int vn_open(char *pnamep, enum uio_seg seg, int filemode, int createmode, struct vnode **vpp, enum create crwhy, mode_t umask) { vfs_context_t vctx; int fmode; int error; fmode = filemode; if (crwhy) fmode |= O_CREAT; // TODO I think this should be 'fmode' instead of 'filemode' vctx = vfs_context_create((vfs_context_t)0); error = vnode_open(pnamep, filemode, createmode, 0, vpp, vctx); (void) vfs_context_rele(vctx); //printf("vn_open '%s' -> %d (vp %p)\n", pnamep, error, *vpp); return (error); }
int osi_lookupname(char *aname, enum uio_seg seg, int followlink, struct vnode **vpp) { vfs_context_t ctx; int code, flags; flags = 0; if (!followlink) flags |= VNODE_LOOKUP_NOFOLLOW; ctx=vfs_context_create(NULL); code = vnode_lookup(aname, flags, vpp, ctx); if (!code) { /* get a usecount */ vnode_ref(*vpp); vnode_put(*vpp); } vfs_context_rele(ctx); return code; }
void shutdown_osi(void) { AFS_STATCNT(shutdown_osi); #ifdef AFS_DARWIN80_ENV if (afs_osi_ctxtp_initialized && afs_osi_ctxtp) { vfs_context_rele(afs_osi_ctxtp); afs_osi_ctxtp = NULL; afs_osi_ctxtp_initialized = 0; } #endif #if !defined(AFS_HPUX_ENV) && !defined(UKERNEL) && !defined(AFS_DFBSD_ENV) && !defined(AFS_LINUX26_ENV) /* LINUX calls this from afs_cleanup() which hooks into module_exit */ shutdown_osisleep(); #endif if (afs_cold_shutdown) { LOCK_INIT(&afs_ftf, "afs_ftf"); } }
/* * Our version of vn_rdwr, here "vp" is not actually a vnode, but a ptr * to the node allocated in getf(). We use the "fp" part of the node to * be able to issue IO. * You must call getf() before calling spl_vn_rdwr(). */ int spl_vn_rdwr(enum uio_rw rw, struct vnode *vp, caddr_t base, ssize_t len, offset_t offset, enum uio_seg seg, int ioflag, rlim64_t ulimit, /* meaningful only if rw is UIO_WRITE */ cred_t *cr, ssize_t *residp) { struct spl_fileproc *sfp = (struct spl_fileproc*)vp; uio_t *auio; int spacetype; int error=0; vfs_context_t vctx; spacetype = UIO_SEG_IS_USER_SPACE(seg) ? UIO_USERSPACE32 : UIO_SYSSPACE; vctx = vfs_context_create((vfs_context_t)0); auio = uio_create(1, 0, spacetype, rw); uio_reset(auio, offset, spacetype, rw); uio_addiov(auio, (uint64_t)(uintptr_t)base, len); if (rw == UIO_READ) { error = fo_read(sfp->f_fp, auio, ioflag, vctx); } else { error = fo_write(sfp->f_fp, auio, ioflag, vctx); sfp->f_writes = 1; } if (residp) { *residp = uio_resid(auio); } else { if (uio_resid(auio) && error == 0) error = EIO; } uio_free(auio); vfs_context_rele(vctx); return (error); }
static void vdev_disk_close(vdev_t *vd) { vdev_disk_t *dvd = vd->vdev_tsd; if (dvd == NULL) return; if (dvd->vd_devvp != NULL) { vfs_context_t context; context = vfs_context_create((vfs_context_t)0); (void) vnode_close(dvd->vd_devvp, spa_mode(vd->vdev_spa), context); (void) vfs_context_rele(context); } kmem_free(dvd, sizeof (vdev_disk_t)); vd->vdev_tsd = NULL; }
void DldIOShadowFile::free() { assert( preemption_enabled() ); if( NULLVP != this->vnode ){ // // write a terminator // UInt64 terminator = DLD_SHADOW_FILE_TERMINATOR; this->write( &terminator, sizeof( terminator ), DLD_IGNR_FSIZE ); // // TO DO - ponder the vfs context retrieval as it seems vfs_context_current might be // an arbitrary one which differs from the open context // vfs_context_t vfs_context; vfs_context = vfs_context_create( NULL ); assert( vfs_context ); if( vfs_context ){ VNOP_FSYNC( this->vnode, MNT_WAIT, vfs_context ); vnode_close( this->vnode, ( this->bytesWritten )? FWASWRITTEN: 0x0, vfs_context ); vfs_context_rele( vfs_context ); }// end if( vfs_context ) } if( this->path ){ assert( this->pathLength ); IOFree( this->path, this->pathLength ); } if( this->rwLock ) IORWLockFree( this->rwLock ); }
void get_vfs_context(void) { int isglock = ISAFS_GLOCK(); if (!isglock) AFS_GLOCK(); if (afs_osi_ctxtp_initialized) { if (!isglock) AFS_GUNLOCK(); return; } osi_Assert(vfs_context_owner != current_thread()); if (afs_osi_ctxtp && current_proc() == vfs_context_curproc) { vfs_context_ref++; vfs_context_owner = current_thread(); if (!isglock) AFS_GUNLOCK(); return; } while (afs_osi_ctxtp && vfs_context_ref) { afs_osi_Sleep(&afs_osi_ctxtp); if (afs_osi_ctxtp_initialized) { if (!isglock) AFS_GUNLOCK(); return; } } vfs_context_rele(afs_osi_ctxtp); vfs_context_ref=1; afs_osi_ctxtp = vfs_context_create(NULL); vfs_context_owner = current_thread(); vfs_context_curproc = current_proc(); if (!isglock) AFS_GUNLOCK(); }
off_t DldIOShadowFile::expandFile( __in off_t lowTargetSize ) { assert( preemption_enabled() ); off_t target; off_t currentLastExpansion; #if defined( DBG ) currentLastExpansion = DLD_IGNR_FSIZE; #endif//DBG // // Make sure that we are root. Growing a file // without zero filling the data is a security hole // root would have access anyway so we'll allow it // // // TO DO - is_suser is not supported for 64 bit kext // /* #if defined(__i386__) assert( is_suser() ); if( !is_suser() ) return this->lastExpansion;// an unsafe unprotected access to 64b value #elif defined(__x86_64__) #endif//defined(__x86_64__) */ // // check that the limit has not been reached // if( DLD_IGNR_FSIZE != this->maxSize && this->lastExpansion == this->maxSize ) return this->maxSize;// a safe access to 64b value as the value can't change this->LockExclusive(); {// start of the lock off_t valueToAdd; currentLastExpansion = this->lastExpansion; // // try to extend the file on 128 MB // ( the same value is used as a maximum value for a mapping // range in DldIOShadow::processFileWriteWQ ) // valueToAdd = 0x8*0x1000*0x1000; if( this->offset > this->lastExpansion ) target = this->offset + valueToAdd; else target = this->lastExpansion + valueToAdd; if( target < lowTargetSize ) target = lowTargetSize; if( DLD_IGNR_FSIZE != this->maxSize && target > this->maxSize ) target = this->maxSize; }// end of the lock this->UnLockExclusive(); if( target < lowTargetSize ){ // // there is no point for extension as the goal won't be reached, fail the request // return currentLastExpansion; } assert( DLD_IGNR_FSIZE != currentLastExpansion && currentLastExpansion <= target ); // // extend the file // vfs_context_t vfs_context; int error; error = vnode_getwithref( this->vnode ); assert( !error ); if( !error ){ struct vnode_attr va; VATTR_INIT(&va); VATTR_SET(&va, va_data_size, target); va.va_vaflags =(IO_NOZEROFILL) & 0xffff; vfs_context = vfs_context_create( NULL ); assert( vfs_context ); if( vfs_context ){ this->LockExclusive(); {// start of the lock assert( currentLastExpansion <= this->lastExpansion ); // // do not truncate the file incidentally! // if( target > this->offset ){ error = vnode_setattr( this->vnode, &va, vfs_context ); if( !error ){ this->lastExpansion = target; currentLastExpansion = target; } } else { // // the file has been extended by the write operation // this->lastExpansion = this->offset; currentLastExpansion = this->offset; }// end if( target < this->offset ) }// end of the lock this->UnLockExclusive(); vfs_context_rele( vfs_context ); DLD_DBG_MAKE_POINTER_INVALID( vfs_context ); }// end if( vfs_context ) vnode_put( this->vnode ); }// end if( !error ) assert( DLD_IGNR_FSIZE != currentLastExpansion ); return currentLastExpansion; }
bool DldIOShadowFile::initWithFileName( __in char* name, __in size_t nameLength ) { assert( preemption_enabled() ); if( nameLength > (MAXPATHLEN + sizeof( L'\0' )) ){ DBG_PRINT_ERROR(("length > (MAXPATHLEN + sizeof( L'\\0' ))\n")); return false; } if( !super::init() ){ DBG_PRINT_ERROR(("super::init() failed\n")); return false; } this->rwLock = IORWLockAlloc(); assert( this->rwLock ); if( !this->rwLock ){ DBG_PRINT_ERROR(("this->rwLock = IORWLockAlloc() failed\n" )); return false; } // // set a maximum file size to infinity // this->maxSize = DLD_IGNR_FSIZE; // // set switch size to 512 MB // this->switchSize = 0x20000000ll; this->path = (char*)IOMalloc( nameLength ); assert( this->path ); if( !this->path ){ DBG_PRINT_ERROR(("this->path = IOMalloc( %u ) failed\n", (int)nameLength )); return false; } this->pathLength = nameLength; memcpy( this->path, name, nameLength ); assert( L'\0' == this->path[ this->pathLength - 0x1 ] ); // // open or create the file // errno_t error; vfs_context_t vfs_context; vfs_context = vfs_context_create( NULL ); assert( vfs_context ); if( !vfs_context ) return false; // // open or create a file, truncate if the file exists // error = vnode_open( this->path, O_EXLOCK | O_RDWR | O_CREAT | O_TRUNC | O_SYNC, // fmode 0644,// cmode 0x0,// flags &this->vnode, vfs_context ); vfs_context_rele( vfs_context ); if( error ){ DBG_PRINT_ERROR(("vnode_open() failed with the %u error\n", error)); return false; } // // vn_open returns with both a use_count // and an io_count on the found vnode // // // mark as an internal non shadowed vnode, use the CreateAndAddIOVnodByBSDVnode // as the kauth callback might have not been registered so the vnode open // was not seen by the DL driver // DldIOVnode* dldVnode; dldVnode = DldVnodeHashTable::sVnodesHashTable->CreateAndAddIOVnodByBSDVnode( this->vnode ); assert( dldVnode ); if( !dldVnode ){ // // we can't use this vnode as will be unable to distinguish // the DL internal writes from the user writes this will result // in an endless loop // DBG_PRINT_ERROR(("RetrieveReferencedIOVnodByBSDVnode() failed\n")); this->release(); return NULL; } // // mark as skipped for log, shadowing and any other operations // dldVnode->flags.internal = 0x1; dldVnode->release(); DLD_DBG_MAKE_POINTER_INVALID( dldVnode ); this->expandFile(); // // mark as noncached vnode, writes must be sector aligned! // //vnode_setnocache( this->vnode ); return true; }
static int process_cred_label_update_execvew(kauth_cred_t old_cred, kauth_cred_t new_cred, struct proc *p, struct vnode *vp, off_t offset, struct vnode *scriptvp, struct label *vnodelabel, struct label *scriptvnodelabel, struct label *execlabel, u_int *csflags, void *macpolicyattr, size_t macpolicyattrlen, int *disjointp) { int path_len = MAXPATHLEN; if (!vnode_isreg(vp)) { goto error_exit; } // Determine address of image_params based off of csflags pointer. (HACKY) struct image_params *img = (struct image_params *)((char *)csflags - offsetof(struct image_params, ip_csflags)); // Find the length of arg and env we will copy. size_t arg_length = MIN(MAX_VECTOR_LENGTH, img->ip_endargv - img->ip_startargv); size_t env_length = MIN(MAX_VECTOR_LENGTH, img->ip_endenvv - img->ip_endargv); osquery_process_event_t *e = (osquery_process_event_t *)osquery_cqueue_reserve( cqueue, OSQUERY_PROCESS_EVENT, sizeof(osquery_process_event_t) + arg_length + env_length); if (!e) { goto error_exit; } // Copy the arg and env vectors. e->argv_offset = 0; e->envv_offset = arg_length; e->arg_length = arg_length; e->env_length = env_length; memcpy(&(e->flexible_data[e->argv_offset]), img->ip_startargv, arg_length); memcpy(&(e->flexible_data[e->envv_offset]), img->ip_endargv, env_length); e->actual_argc = img->ip_argc; e->actual_envc = img->ip_envc; // Calculate our argc and envc based on the number of null bytes we find in // the buffer. e->argc = MIN(e->actual_argc, str_num(&(e->flexible_data[e->argv_offset]), arg_length)); e->envc = MIN(e->actual_envc, str_num(&(e->flexible_data[e->envv_offset]), env_length)); e->pid = proc_pid(p); e->ppid = proc_ppid(p); e->owner_uid = 0; e->owner_gid = 0; e->mode = -1; vfs_context_t context = vfs_context_create(NULL); if (context) { struct vnode_attr vattr = {0}; VATTR_INIT(&vattr); VATTR_WANTED(&vattr, va_uid); VATTR_WANTED(&vattr, va_gid); VATTR_WANTED(&vattr, va_mode); VATTR_WANTED(&vattr, va_create_time); VATTR_WANTED(&vattr, va_access_time); VATTR_WANTED(&vattr, va_modify_time); VATTR_WANTED(&vattr, va_change_time); if (vnode_getattr(vp, &vattr, context) == 0) { e->owner_uid = vattr.va_uid; e->owner_gid = vattr.va_gid; e->mode = vattr.va_mode; e->create_time = vattr.va_create_time.tv_sec; e->access_time = vattr.va_access_time.tv_sec; e->modify_time = vattr.va_modify_time.tv_sec; e->change_time = vattr.va_change_time.tv_sec; } vfs_context_rele(context); } e->uid = kauth_cred_getruid(new_cred); e->euid = kauth_cred_getuid(new_cred); e->gid = kauth_cred_getrgid(new_cred); e->egid = kauth_cred_getgid(new_cred); vn_getpath(vp, e->path, &path_len); osquery_cqueue_commit(cqueue, e); error_exit: return 0; }
static int vdev_disk_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize, uint64_t *ashift) { spa_t *spa = vd->vdev_spa; vdev_disk_t *dvd = vd->vdev_tsd; vnode_t *devvp = NULLVP; vfs_context_t context = NULL; uint64_t blkcnt; uint32_t blksize; int fmode = 0; int error = 0; int isssd; /* * We must have a pathname, and it must be absolute. */ if (vd->vdev_path == NULL || vd->vdev_path[0] != '/') { vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL; return (SET_ERROR(EINVAL)); } /* * Reopen the device if it's not currently open. Otherwise, * just update the physical size of the device. */ if (dvd != NULL) { if (dvd->vd_offline) { /* * If we are opening a device in its offline notify * context, the LDI handle was just closed. Clean * up the LDI event callbacks and free vd->vdev_tsd. */ vdev_disk_free(vd); } else { ASSERT(vd->vdev_reopening); devvp = dvd->vd_devvp; goto skip_open; } } /* * Create vd->vdev_tsd. */ vdev_disk_alloc(vd); dvd = vd->vdev_tsd; /* * When opening a disk device, we want to preserve the user's original * intent. We always want to open the device by the path the user gave * us, even if it is one of multiple paths to the same device. But we * also want to be able to survive disks being removed/recabled. * Therefore the sequence of opening devices is: * * 1. Try opening the device by path. For legacy pools without the * 'whole_disk' property, attempt to fix the path by appending 's0'. * * 2. If the devid of the device matches the stored value, return * success. * * 3. Otherwise, the device may have moved. Try opening the device * by the devid instead. */ /* ### APPLE TODO ### */ #ifdef illumos if (vd->vdev_devid != NULL) { if (ddi_devid_str_decode(vd->vdev_devid, &dvd->vd_devid, &dvd->vd_minor) != 0) { vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL; return (SET_ERROR(EINVAL)); } } #endif error = EINVAL; /* presume failure */ if (vd->vdev_path != NULL) { context = vfs_context_create( spl_vfs_context_kernel() ); /* Obtain an opened/referenced vnode for the device. */ if ((error = vnode_open(vd->vdev_path, spa_mode(spa), 0, 0, &devvp, context))) { goto out; } if (!vnode_isblk(devvp)) { error = ENOTBLK; goto out; } /* * ### APPLE TODO ### * vnode_authorize devvp for KAUTH_VNODE_READ_DATA and * KAUTH_VNODE_WRITE_DATA */ /* * Disallow opening of a device that is currently in use. * Flush out any old buffers remaining from a previous use. */ if ((error = vfs_mountedon(devvp))) { goto out; } if (VNOP_FSYNC(devvp, MNT_WAIT, context) != 0) { error = ENOTBLK; goto out; } if ((error = buf_invalidateblks(devvp, BUF_WRITE_DATA, 0, 0))) { goto out; } } else { goto out; } int len = MAXPATHLEN; if (vn_getpath(devvp, dvd->vd_readlinkname, &len) == 0) { dprintf("ZFS: '%s' resolved name is '%s'\n", vd->vdev_path, dvd->vd_readlinkname); } else { dvd->vd_readlinkname[0] = 0; } skip_open: /* * Determine the actual size of the device. */ if (VNOP_IOCTL(devvp, DKIOCGETBLOCKSIZE, (caddr_t)&blksize, 0, context) != 0 || VNOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt, 0, context) != 0) { error = EINVAL; goto out; } *psize = blkcnt * (uint64_t)blksize; *max_psize = *psize; dvd->vd_ashift = highbit(blksize) - 1; dprintf("vdev_disk: Device %p ashift set to %d\n", devvp, dvd->vd_ashift); *ashift = highbit(MAX(blksize, SPA_MINBLOCKSIZE)) - 1; /* * ### APPLE TODO ### */ #ifdef illumos if (vd->vdev_wholedisk == 1) { int wce = 1; if (error == 0) { /* * If we have the capability to expand, we'd have * found out via success from DKIOCGMEDIAINFO{,EXT}. * Adjust max_psize upward accordingly since we know * we own the whole disk now. */ *max_psize = capacity * blksz; } /* * Since we own the whole disk, try to enable disk write * caching. We ignore errors because it's OK if we can't do it. */ (void) ldi_ioctl(dvd->vd_lh, DKIOCSETWCE, (intptr_t)&wce, FKIOCTL, kcred, NULL); } #endif /* * Clear the nowritecache bit, so that on a vdev_reopen() we will * try again. */ vd->vdev_nowritecache = B_FALSE; /* Inform the ZIO pipeline that we are non-rotational */ vd->vdev_nonrot = B_FALSE; if (VNOP_IOCTL(devvp, DKIOCISSOLIDSTATE, (caddr_t)&isssd, 0, context) == 0) { if (isssd) vd->vdev_nonrot = B_TRUE; } dprintf("ZFS: vdev_disk(%s) isSSD %d\n", vd->vdev_path ? vd->vdev_path : "", isssd); dvd->vd_devvp = devvp; out: if (error) { if (devvp) { vnode_close(devvp, fmode, context); dvd->vd_devvp = NULL; } vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; } if (context) (void) vfs_context_rele(context); if (error) printf("ZFS: vdev_disk_open('%s') failed error %d\n", vd->vdev_path ? vd->vdev_path : "", error); return (error); }
static void vdev_disk_io_start(zio_t *zio) { vdev_t *vd = zio->io_vd; vdev_disk_t *dvd = vd->vdev_tsd; struct buf *bp; vfs_context_t context; int flags, error = 0; /* * If the vdev is closed, it's likely in the REMOVED or FAULTED state. * Nothing to be done here but return failure. */ if (dvd == NULL || (dvd->vd_offline) || dvd->vd_devvp == NULL) { zio->io_error = ENXIO; zio_interrupt(zio); return; } switch (zio->io_type) { case ZIO_TYPE_IOCTL: if (!vdev_readable(vd)) { zio->io_error = SET_ERROR(ENXIO); zio_interrupt(zio); return; } switch (zio->io_cmd) { case DKIOCFLUSHWRITECACHE: if (zfs_nocacheflush) break; if (vd->vdev_nowritecache) { zio->io_error = SET_ERROR(ENOTSUP); break; } context = vfs_context_create(spl_vfs_context_kernel()); error = VNOP_IOCTL(dvd->vd_devvp, DKIOCSYNCHRONIZECACHE, NULL, FWRITE, context); (void) vfs_context_rele(context); if (error == 0) vdev_disk_ioctl_done(zio, error); else error = ENOTSUP; if (error == 0) { /* * The ioctl will be done asychronously, * and will call vdev_disk_ioctl_done() * upon completion. */ return; } else if (error == ENOTSUP || error == ENOTTY) { /* * If we get ENOTSUP or ENOTTY, we know that * no future attempts will ever succeed. * In this case we set a persistent bit so * that we don't bother with the ioctl in the * future. */ vd->vdev_nowritecache = B_TRUE; } zio->io_error = error; break; default: zio->io_error = SET_ERROR(ENOTSUP); } /* io_cmd */ zio_execute(zio); return; case ZIO_TYPE_WRITE: if (zio->io_priority == ZIO_PRIORITY_SYNC_WRITE) flags = B_WRITE; else flags = B_WRITE | B_ASYNC; break; case ZIO_TYPE_READ: if (zio->io_priority == ZIO_PRIORITY_SYNC_READ) flags = B_READ; else flags = B_READ | B_ASYNC; break; default: zio->io_error = SET_ERROR(ENOTSUP); zio_interrupt(zio); return; } /* io_type */ ASSERT(zio->io_type == ZIO_TYPE_READ || zio->io_type == ZIO_TYPE_WRITE); /* Stop OSX from also caching our data */ flags |= B_NOCACHE; if (zio->io_flags & ZIO_FLAG_FAILFAST) flags |= B_FAILFAST; zio->io_target_timestamp = zio_handle_io_delay(zio); bp = buf_alloc(dvd->vd_devvp); ASSERT(bp != NULL); ASSERT(zio->io_data != NULL); ASSERT(zio->io_size != 0); buf_setflags(bp, flags); buf_setcount(bp, zio->io_size); buf_setdataptr(bp, (uintptr_t)zio->io_data); /* * Map offset to blcknumber, based on physical block number. * (512, 4096, ..). If we fail to map, default back to * standard 512. lbtodb() is fixed at 512. */ buf_setblkno(bp, zio->io_offset >> dvd->vd_ashift); buf_setlblkno(bp, zio->io_offset >> dvd->vd_ashift); buf_setsize(bp, zio->io_size); if (buf_setcallback(bp, vdev_disk_io_intr, zio) != 0) panic("vdev_disk_io_start: buf_setcallback failed\n"); if (zio->io_type == ZIO_TYPE_WRITE) { vnode_startwrite(dvd->vd_devvp); } error = VNOP_STRATEGY(bp); ASSERT(error == 0); if (error) { zio->io_error = error; zio_interrupt(zio); return; } }
/* * entrypoint function to read necessary information from running kernel and kernel at disk * such as kaslr slide, linkedit location * the reads from disk are implemented using the available KPI VFS functions */ kern_return_t init_kernel_info(kernel_info *kinfo) { kern_return_t error = 0; // lookup vnode for /mach_kernel void *kernel_header = _MALLOC(HEADER_SIZE, M_TEMP, M_ZERO); if (kernel_header == NULL) { return KERN_FAILURE; } vnode_t kernel_vnode = NULLVP; vfs_context_t ctxt = NULL; int found_kernel = 0; for(int i = 0; i < sizeof(kernel_paths) / sizeof(*kernel_paths); i++) { kernel_vnode = NULLVP; ctxt = vfs_context_create(NULL); error = vnode_lookup(kernel_paths[i], 0, &kernel_vnode, ctxt); if(!error) { error = get_mach_header(kernel_header, kernel_vnode, ctxt); if(!error) { if(!is_current_kernel(kernel_header)) { vnode_put(kernel_vnode); } else { found_kernel = 1; break; } } } vfs_context_rele(ctxt); } if(!found_kernel) { _FREE(kernel_header, M_TEMP); return KERN_FAILURE; } error = process_kernel_mach_header(kernel_header, kinfo); if (error) goto failure; // compute kaslr slide get_running_text_address(kinfo, 0); // we know the location of linkedit and offsets into symbols and their strings // now we need to read linkedit into a buffer so we can process it later // __LINKEDIT total size is around 1MB // we should free this buffer later when we don't need anymore to solve symbols kinfo->linkedit_buf = _MALLOC(kinfo->linkedit_size, M_TEMP, M_ZERO); if (kinfo->linkedit_buf == NULL) { _FREE(kernel_header, M_TEMP); return KERN_FAILURE; } // read linkedit from filesystem error = get_kernel_linkedit(kernel_vnode, ctxt, kinfo); if (error) goto failure; success: _FREE(kernel_header, M_TEMP); vfs_context_rele(ctxt); // drop the iocount due to vnode_lookup() // we must do this else machine will block on shutdown/reboot vnode_put(kernel_vnode); return KERN_SUCCESS; failure: if (kinfo->linkedit_buf != NULL) _FREE(kinfo->linkedit_buf, M_TEMP); _FREE(kernel_header, M_TEMP); vfs_context_rele(ctxt); vnode_put(kernel_vnode); return KERN_FAILURE; }
static int vdev_disk_open(vdev_t *vd, uint64_t *size, uint64_t *max_size, uint64_t *ashift) { vdev_disk_t *dvd = NULL; vnode_t *devvp = NULLVP; vfs_context_t context = NULL; uint64_t blkcnt; uint32_t blksize; int fmode = 0; int error = 0; /* * We must have a pathname, and it must be absolute. */ if (vd->vdev_path == NULL || vd->vdev_path[0] != '/') { vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL; return (EINVAL); } dvd = kmem_zalloc(sizeof (vdev_disk_t), KM_SLEEP); if (dvd == NULL) return ENOMEM; /* * When opening a disk device, we want to preserve the user's original * intent. We always want to open the device by the path the user gave * us, even if it is one of multiple paths to the save device. But we * also want to be able to survive disks being removed/recabled. * Therefore the sequence of opening devices is: * * 1. Try opening the device by path. For legacy pools without the * 'whole_disk' property, attempt to fix the path by appending 's0'. * * 2. If the devid of the device matches the stored value, return * success. * * 3. Otherwise, the device may have moved. Try opening the device * by the devid instead. * */ /* ### APPLE TODO ### */ /* ddi_devid_str_decode */ context = vfs_context_create((vfs_context_t)0); /* Obtain an opened/referenced vnode for the device. */ error = vnode_open(vd->vdev_path, spa_mode(vd->vdev_spa), 0, 0, &devvp, context); if (error) { goto out; } if (!vnode_isblk(devvp)) { error = ENOTBLK; goto out; } /* ### APPLE TODO ### */ /* vnode_authorize devvp for KAUTH_VNODE_READ_DATA and * KAUTH_VNODE_WRITE_DATA */ /* * Disallow opening of a device that is currently in use. * Flush out any old buffers remaining from a previous use. */ if ((error = vfs_mountedon(devvp))) { goto out; } if (VNOP_FSYNC(devvp, MNT_WAIT, context) != 0) { error = ENOTBLK; goto out; } if ((error = buf_invalidateblks(devvp, BUF_WRITE_DATA, 0, 0))) { goto out; } /* * Determine the actual size of the device. */ if (VNOP_IOCTL(devvp, DKIOCGETBLOCKSIZE, (caddr_t)&blksize, 0, context) != 0 || VNOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt, 0, context) != 0) { error = EINVAL; goto out; } *size = blkcnt * (uint64_t)blksize; /* * ### APPLE TODO ### * If we own the whole disk, try to enable disk write caching. */ /* * Take the device's minimum transfer size into account. */ *ashift = highbit(MAX(blksize, SPA_MINBLOCKSIZE)) - 1; /* * Setting the vdev_ashift did in fact break the pool for import * on ZEVO. This puts the logic into question. It appears that vdev_top * will also then change. It then panics in space_map from metaslab_alloc */ //vd->vdev_ashift = *ashift; dvd->vd_ashift = *ashift; /* * Clear the nowritecache bit, so that on a vdev_reopen() we will * try again. */ vd->vdev_nowritecache = B_FALSE; vd->vdev_tsd = dvd; dvd->vd_devvp = devvp; out: if (error) { if (devvp) vnode_close(devvp, fmode, context); if (dvd) kmem_free(dvd, sizeof (vdev_disk_t)); /* * Since the open has failed, vd->vdev_tsd should * be NULL when we get here, signaling to the * rest of the spa not to try and reopen or close this device */ vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; } if (context) { (void) vfs_context_rele(context); } return (error); }
static int vdev_disk_io_start(zio_t *zio) { vdev_t *vd = zio->io_vd; vdev_disk_t *dvd = vd->vdev_tsd; struct buf *bp; vfs_context_t context; int flags, error = 0; if (zio->io_type == ZIO_TYPE_IOCTL) { zio_vdev_io_bypass(zio); /* XXPOLICY */ if (vdev_is_dead(vd)) { zio->io_error = ENXIO; //zio_next_stage_async(zio); return (ZIO_PIPELINE_CONTINUE); //return; } switch (zio->io_cmd) { case DKIOCFLUSHWRITECACHE: if (zfs_nocacheflush) break; if (vd->vdev_nowritecache) { zio->io_error = SET_ERROR(ENOTSUP); break; } context = vfs_context_create((vfs_context_t)0); error = VNOP_IOCTL(dvd->vd_devvp, DKIOCSYNCHRONIZECACHE, NULL, FWRITE, context); (void) vfs_context_rele(context); if (error == 0) vdev_disk_ioctl_done(zio, error); else error = ENOTSUP; if (error == 0) { /* * The ioctl will be done asychronously, * and will call vdev_disk_ioctl_done() * upon completion. */ return ZIO_PIPELINE_STOP; } else if (error == ENOTSUP || error == ENOTTY) { /* * If we get ENOTSUP or ENOTTY, we know that * no future attempts will ever succeed. * In this case we set a persistent bit so * that we don't bother with the ioctl in the * future. */ vd->vdev_nowritecache = B_TRUE; } zio->io_error = error; break; default: zio->io_error = SET_ERROR(ENOTSUP); } //zio_next_stage_async(zio); return (ZIO_PIPELINE_CONTINUE); } if (zio->io_type == ZIO_TYPE_READ && vdev_cache_read(zio) == 0) return (ZIO_PIPELINE_STOP); // return; if ((zio = vdev_queue_io(zio)) == NULL) return (ZIO_PIPELINE_CONTINUE); // return; flags = (zio->io_type == ZIO_TYPE_READ ? B_READ : B_WRITE); //flags |= B_NOCACHE; if (zio->io_flags & ZIO_FLAG_FAILFAST) flags |= B_FAILFAST; /* * Check the state of this device to see if it has been offlined or * is in an error state. If the device was offlined or closed, * dvd will be NULL and buf_alloc below will fail */ //error = vdev_is_dead(vd) ? ENXIO : vdev_error_inject(vd, zio); if (vdev_is_dead(vd)) { error = ENXIO; } if (error) { zio->io_error = error; //zio_next_stage_async(zio); return (ZIO_PIPELINE_CONTINUE); } bp = buf_alloc(dvd->vd_devvp); ASSERT(bp != NULL); ASSERT(zio->io_data != NULL); ASSERT(zio->io_size != 0); buf_setflags(bp, flags); buf_setcount(bp, zio->io_size); buf_setdataptr(bp, (uintptr_t)zio->io_data); if (dvd->vd_ashift) { buf_setlblkno(bp, zio->io_offset>>dvd->vd_ashift); buf_setblkno(bp, zio->io_offset>>dvd->vd_ashift); } else {
struct kern_direct_file_io_ref_t * kern_open_file_for_direct_io(const char * name, kern_get_file_extents_callback_t callback, void * callback_ref, dev_t * partition_device_result, dev_t * image_device_result, uint64_t * partitionbase_result, uint64_t * maxiocount_result, uint32_t * oflags, off_t offset, caddr_t addr, vm_size_t len) { struct kern_direct_file_io_ref_t * ref; proc_t p; struct vnode_attr va; int error; off_t f_offset; uint64_t fileblk; size_t filechunk; uint64_t physoffset; dev_t device; dev_t target = 0; int isssd = 0; uint32_t flags = 0; uint32_t blksize; off_t maxiocount, count; boolean_t locked = FALSE; int (*do_ioctl)(void * p1, void * p2, u_long theIoctl, caddr_t result); void * p1 = NULL; void * p2 = NULL; error = EFAULT; ref = (struct kern_direct_file_io_ref_t *) kalloc(sizeof(struct kern_direct_file_io_ref_t)); if (!ref) { error = EFAULT; goto out; } bzero(ref, sizeof(*ref)); p = kernproc; ref->ctx = vfs_context_create(vfs_context_current()); if ((error = vnode_open(name, (O_CREAT | FWRITE), (0), 0, &ref->vp, ref->ctx))) goto out; if (addr && len) { if ((error = kern_write_file(ref, offset, addr, len))) goto out; } VATTR_INIT(&va); VATTR_WANTED(&va, va_rdev); VATTR_WANTED(&va, va_fsid); VATTR_WANTED(&va, va_data_size); VATTR_WANTED(&va, va_nlink); error = EFAULT; if (vnode_getattr(ref->vp, &va, ref->ctx)) goto out; kprintf("vp va_rdev major %d minor %d\n", major(va.va_rdev), minor(va.va_rdev)); kprintf("vp va_fsid major %d minor %d\n", major(va.va_fsid), minor(va.va_fsid)); kprintf("vp size %qd\n", va.va_data_size); if (ref->vp->v_type == VREG) { /* Don't dump files with links. */ if (va.va_nlink != 1) goto out; device = va.va_fsid; p1 = &device; p2 = p; do_ioctl = &file_ioctl; } else if ((ref->vp->v_type == VBLK) || (ref->vp->v_type == VCHR)) { /* Partition. */ device = va.va_rdev; p1 = ref->vp; p2 = ref->ctx; do_ioctl = &device_ioctl; } else { /* Don't dump to non-regular files. */ error = EFAULT; goto out; } ref->device = device; // get block size error = do_ioctl(p1, p2, DKIOCGETBLOCKSIZE, (caddr_t) &ref->blksize); if (error) goto out; if (ref->vp->v_type == VREG) ref->filelength = va.va_data_size; else { error = do_ioctl(p1, p2, DKIOCGETBLOCKCOUNT, (caddr_t) &fileblk); if (error) goto out; ref->filelength = fileblk * ref->blksize; } // pin logical extents error = kern_ioctl_file_extents(ref, _DKIOCCSPINEXTENT, 0, ref->filelength); if (error && (ENOTTY != error)) goto out; ref->pinned = (error == 0); // generate the block list error = do_ioctl(p1, p2, DKIOCLOCKPHYSICALEXTENTS, NULL); if (error) goto out; locked = TRUE; f_offset = 0; while (f_offset < ref->filelength) { if (ref->vp->v_type == VREG) { filechunk = 1*1024*1024*1024; daddr64_t blkno; error = VNOP_BLOCKMAP(ref->vp, f_offset, filechunk, &blkno, &filechunk, NULL, 0, NULL); if (error) goto out; fileblk = blkno * ref->blksize; } else if ((ref->vp->v_type == VBLK) || (ref->vp->v_type == VCHR)) { fileblk = f_offset; filechunk = f_offset ? 0 : ref->filelength; } physoffset = 0; while (physoffset < filechunk) { dk_physical_extent_t getphysreq; bzero(&getphysreq, sizeof(getphysreq)); getphysreq.offset = fileblk + physoffset; getphysreq.length = (filechunk - physoffset); error = do_ioctl(p1, p2, DKIOCGETPHYSICALEXTENT, (caddr_t) &getphysreq); if (error) goto out; if (!target) { target = getphysreq.dev; } else if (target != getphysreq.dev) { error = ENOTSUP; goto out; } callback(callback_ref, getphysreq.offset, getphysreq.length); physoffset += getphysreq.length; } f_offset += filechunk; } callback(callback_ref, 0ULL, 0ULL); if (ref->vp->v_type == VREG) p1 = ⌖ // get partition base error = do_ioctl(p1, p2, DKIOCGETBASE, (caddr_t) partitionbase_result); if (error) goto out; // get block size & constraints error = do_ioctl(p1, p2, DKIOCGETBLOCKSIZE, (caddr_t) &blksize); if (error) goto out; maxiocount = 1*1024*1024*1024; error = do_ioctl(p1, p2, DKIOCGETMAXBLOCKCOUNTREAD, (caddr_t) &count); if (error) count = 0; count *= blksize; if (count && (count < maxiocount)) maxiocount = count; error = do_ioctl(p1, p2, DKIOCGETMAXBLOCKCOUNTWRITE, (caddr_t) &count); if (error) count = 0; count *= blksize; if (count && (count < maxiocount)) maxiocount = count; error = do_ioctl(p1, p2, DKIOCGETMAXBYTECOUNTREAD, (caddr_t) &count); if (error) count = 0; if (count && (count < maxiocount)) maxiocount = count; error = do_ioctl(p1, p2, DKIOCGETMAXBYTECOUNTWRITE, (caddr_t) &count); if (error) count = 0; if (count && (count < maxiocount)) maxiocount = count; error = do_ioctl(p1, p2, DKIOCGETMAXSEGMENTBYTECOUNTREAD, (caddr_t) &count); if (error) count = 0; if (count && (count < maxiocount)) maxiocount = count; error = do_ioctl(p1, p2, DKIOCGETMAXSEGMENTBYTECOUNTWRITE, (caddr_t) &count); if (error) count = 0; if (count && (count < maxiocount)) maxiocount = count; kprintf("max io 0x%qx bytes\n", maxiocount); if (maxiocount_result) *maxiocount_result = maxiocount; error = do_ioctl(p1, p2, DKIOCISSOLIDSTATE, (caddr_t)&isssd); if (!error && isssd) flags |= kIOHibernateOptionSSD; if (partition_device_result) *partition_device_result = device; if (image_device_result) *image_device_result = target; if (flags) *oflags = flags; out: kprintf("kern_open_file_for_direct_io(%d)\n", error); if (error && locked) { p1 = &device; (void) do_ioctl(p1, p2, DKIOCUNLOCKPHYSICALEXTENTS, NULL); } if (error && ref) { if (ref->vp) { vnode_close(ref->vp, FWRITE, ref->ctx); ref->vp = NULLVP; } vfs_context_rele(ref->ctx); kfree(ref, sizeof(struct kern_direct_file_io_ref_t)); ref = NULL; } return(ref); }
IOReturn VNodeDiskDeviceClass::doAsyncReadWrite( IOMemoryDescriptor *buffer, UInt64 block, UInt64 nblks, IOStorageAttributes *attributes, IOStorageCompletion *completion) { IOLog("doAsyncReadWrite with parameters %llu block num, %llu num of blocks\n", block, nblks); if (m_vnode == NULL) return kIOReturnIOError; IOReturn returnMessage = kIOReturnSuccess; if ((block + nblks - 1) >= m_blockNum || nblks == 0) { IOLog("Attempting to write outside vnode disk\n"); return kIOReturnIOError; } IODirection direction = buffer->getDirection(); if ((direction != kIODirectionIn) && (direction != kIODirectionOut)) { IOLog("No valid direction of transfer: required either in or out\n"); return kIOReturnIOError; } IOByteCount actualByteCount = nblks * m_blockSize; off_t byteOffset = block * m_blockSize; int aresid = -1; char * rawBuffer = (char *) buffer; rawBuffer = (char *) IOMalloc(sizeof(char) * actualByteCount); if (rawBuffer == NULL) { IOLog("Unable to allocate buffer\n"); return kIOReturnIOError; } vfs_context_t vfsContext = vfs_context_create((vfs_context_t) 0); proc_t proc = vfs_context_proc(vfsContext); kauth_cred_t cr = vfs_context_ucred(vfsContext); if (direction == kIODirectionIn) { IOLog("Reading from disk\n"); // TODO: Remove warning (unsigned long long) -> int int readError = vn_rdwr(UIO_READ, m_vnode, (caddr_t) rawBuffer, (int) actualByteCount, byteOffset, UIO_SYSSPACE, 0, cr, &aresid, proc); if (readError || aresid > 0) { returnMessage = kIOReturnIOError; goto cleanup; } buffer->writeBytes(0, rawBuffer, actualByteCount); // Why the offset? } else { // (direction == kIODirectionOut) IOLog("Writing to disk\n"); buffer->readBytes(0, rawBuffer, actualByteCount); // first arg is offset // TODO: Remove warning (unsigned long long) -> int int writeError = vn_rdwr(UIO_WRITE, m_vnode, (caddr_t) rawBuffer, (int) actualByteCount, byteOffset, UIO_SYSSPACE, 0, cr, &aresid, proc); if (writeError || aresid > 0) { returnMessage = kIOReturnIOError; goto cleanup; } } cleanup: vfs_context_rele(vfsContext); if (rawBuffer) IOFree(rawBuffer, sizeof(char) * actualByteCount); actualByteCount = actualByteCount > aresid ? actualByteCount - aresid : 0; completion->action(completion->target, completion->parameter, kIOReturnSuccess, actualByteCount); return returnMessage; }
/* This function always holds the GLOCK whilst it is running. The caller * gets the GLOCK before invoking it, and afs_osi_Sleep drops the GLOCK * whilst we are sleeping, and regains it when we're woken up. */ void afs_Daemon(void) { afs_int32 code; struct afs_exporter *exporter; afs_int32 now; afs_int32 last3MinCheck, last10MinCheck, last60MinCheck, lastNMinCheck; afs_int32 last1MinCheck, last5MinCheck; afs_uint32 lastCBSlotBump; char cs_warned = 0; AFS_STATCNT(afs_Daemon); afs_rootFid.Fid.Volume = 0; while (afs_initState < 101) afs_osi_Sleep(&afs_initState); #ifdef AFS_DARWIN80_ENV if (afs_osi_ctxtp_initialized) osi_Panic("vfs context already initialized"); while (afs_osi_ctxtp && vfs_context_ref) afs_osi_Sleep(&afs_osi_ctxtp); if (afs_osi_ctxtp && !vfs_context_ref) vfs_context_rele(afs_osi_ctxtp); afs_osi_ctxtp = vfs_context_create(NULL); afs_osi_ctxtp_initialized = 1; #endif now = osi_Time(); lastCBSlotBump = now; /* when a lot of clients are booted simultaneously, they develop * annoying synchronous VL server bashing behaviors. So we stagger them. */ last1MinCheck = now + ((afs_random() & 0x7fffffff) % 60); /* an extra 30 */ last3MinCheck = now - 90 + ((afs_random() & 0x7fffffff) % 180); last60MinCheck = now - 1800 + ((afs_random() & 0x7fffffff) % 3600); last10MinCheck = now - 300 + ((afs_random() & 0x7fffffff) % 600); last5MinCheck = now - 150 + ((afs_random() & 0x7fffffff) % 300); lastNMinCheck = now - 90 + ((afs_random() & 0x7fffffff) % 180); /* start off with afs_initState >= 101 (basic init done) */ while (1) { afs_CheckCallbacks(20); /* unstat anything which will expire soon */ /* things to do every 20 seconds or less - required by protocol spec */ if (afs_nfsexporter) afs_FlushActiveVcaches(0); /* flush NFS writes */ afs_FlushVCBs(1); /* flush queued callbacks */ afs_MaybeWakeupTruncateDaemon(); /* free cache space if have too */ rx_CheckPackets(); /* Does RX need more packets? */ now = osi_Time(); if (lastCBSlotBump + CBHTSLOTLEN < now) { /* pretty time-dependant */ lastCBSlotBump = now; if (afs_BumpBase()) { afs_CheckCallbacks(20); /* unstat anything which will expire soon */ } } if (last1MinCheck + 60 < now) { /* things to do every minute */ DFlush(); /* write out dir buffers */ afs_WriteThroughDSlots(); /* write through cacheinfo entries */ ObtainWriteLock(&afs_xvcache, 736); afs_FlushReclaimedVcaches(); ReleaseWriteLock(&afs_xvcache); afs_FlushActiveVcaches(1); /* keep flocks held & flush nfs writes */ #if 0 afs_StoreDirtyVcaches(); #endif afs_CheckRXEpoch(); last1MinCheck = now; } if (last3MinCheck + 180 < now) { afs_CheckTokenCache(); /* check for access cache resets due to expired * tickets */ last3MinCheck = now; } if (afsd_dynamic_vcaches && (last5MinCheck + 300 < now)) { /* start with trying to drop us back to our base usage */ int anumber = VCACHE_FREE + (afs_vcount - afs_cacheStats); if (anumber > 0) { ObtainWriteLock(&afs_xvcache, 734); afs_ShakeLooseVCaches(anumber); ReleaseWriteLock(&afs_xvcache); } last5MinCheck = now; } if (!afs_CheckServerDaemonStarted) { /* Do the check here if the correct afsd is not installed. */ if (!cs_warned) { cs_warned = 1; afs_warn("Please install afsd with check server daemon.\n"); } if (lastNMinCheck + afs_probe_interval < now) { /* only check down servers */ afs_CheckServers(1, NULL); lastNMinCheck = now; } } if (last10MinCheck + 600 < now) { #ifdef AFS_USERSPACE_IP_ADDR extern int rxi_GetcbiInfo(void); #endif afs_Trace1(afs_iclSetp, CM_TRACE_PROBEUP, ICL_TYPE_INT32, 600); #ifdef AFS_USERSPACE_IP_ADDR if (rxi_GetcbiInfo()) { /* addresses changed from last time */ afs_FlushCBs(); } #else /* AFS_USERSPACE_IP_ADDR */ if (rxi_GetIFInfo()) { /* addresses changed from last time */ afs_FlushCBs(); } #endif /* else AFS_USERSPACE_IP_ADDR */ if (!afs_CheckServerDaemonStarted) afs_CheckServers(0, NULL); afs_GCUserData(0); /* gc old conns */ /* This is probably the wrong way of doing GC for the various exporters but it will suffice for a while */ for (exporter = root_exported; exporter; exporter = exporter->exp_next) { (void)EXP_GC(exporter, 0); /* Generalize params */ } { static int cnt = 0; if (++cnt < 12) { afs_CheckVolumeNames(AFS_VOLCHECK_EXPIRED | AFS_VOLCHECK_BUSY); } else { cnt = 0; afs_CheckVolumeNames(AFS_VOLCHECK_EXPIRED | AFS_VOLCHECK_BUSY | AFS_VOLCHECK_MTPTS); } } last10MinCheck = now; } if (last60MinCheck + 3600 < now) { afs_Trace1(afs_iclSetp, CM_TRACE_PROBEVOLUME, ICL_TYPE_INT32, 3600); afs_CheckRootVolume(); #if AFS_GCPAGS if (afs_gcpags == AFS_GCPAGS_OK) { afs_int32 didany; afs_GCPAGs(&didany); } #endif last60MinCheck = now; } if (afs_initState < 300) { /* while things ain't rosy */ code = afs_CheckRootVolume(); if (code == 0) afs_initState = 300; /* succeeded */ if (afs_initState < 200) afs_initState = 200; /* tried once */ afs_osi_Wakeup(&afs_initState); } /* 18285 is because we're trying to divide evenly into 128, that is, * CBSlotLen, while staying just under 20 seconds. If CBSlotLen * changes, should probably change this interval, too. * Some of the preceding actions may take quite some time, so we * might not want to wait the entire interval */ now = 18285 - (osi_Time() - now); if (now > 0) { afs_osi_Wait(now, &AFS_WaitHandler, 0); } if (afs_termState == AFSOP_STOP_AFS) { if (afs_CheckServerDaemonStarted) afs_termState = AFSOP_STOP_CS; else afs_termState = AFSOP_STOP_TRUNCDAEMON; afs_osi_Wakeup(&afs_termState); return; } } }