static int vdev_file_open(vdev_t *vd, uint64_t *psize, uint64_t *ashift) { vdev_file_t *vf; #ifdef __APPLE__ struct vnode *vp, *rootdir; struct vnode_attr vattr; vfs_context_t context; #else vnode_t *vp; vattr_t vattr; #endif int error; /* * 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); } vf = vd->vdev_tsd = kmem_zalloc(sizeof (vdev_file_t), KM_SLEEP); /* * We always open the files from the root of the global zone, even if * we're in a local zone. If the user has gotten to this point, the * administrator has already decided that the pool should be available * to local zone users, so the underlying devices should be as well. */ ASSERT(vd->vdev_path != NULL && vd->vdev_path[0] == '/'); #ifdef __APPLE__ rootdir = getrootdir(); #endif error = vn_openat(vd->vdev_path + 1, UIO_SYSSPACE, spa_mode | FOFFMAX, 0, &vp, 0, 0, rootdir); if (error) { vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; return (error); } vf->vf_vnode = vp; #ifdef _KERNEL /* * Make sure it's a regular file. */ #ifdef __APPLE__ if (!vnode_isreg(vp)) { #else if (vp->v_type != VREG) { #endif vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; return (ENODEV); } #endif /* * Determine the physical size of the file. */ #ifdef __APPLE__ VATTR_INIT(&vattr); VATTR_WANTED(&vattr, va_data_size); context = vfs_context_create((vfs_context_t)0); error = vnode_getattr(vp, &vattr, context); (void) vfs_context_rele(context); if (error || !VATTR_IS_SUPPORTED(&vattr, va_data_size)) { vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; return (error); } *psize = vattr.va_data_size; #else vattr.va_mask = AT_SIZE; error = VOP_GETATTR(vp, &vattr, 0, kcred); if (error) { vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; return (error); } *psize = vattr.va_size; #endif *ashift = SPA_MINBLOCKSHIFT; return (0); } static void vdev_file_close(vdev_t *vd) { vdev_file_t *vf = vd->vdev_tsd; if (vf == NULL) return; if (vf->vf_vnode != NULL) { #ifdef __APPLE__ vfs_context_t context; context = vfs_context_create((vfs_context_t)0); /* ### APPLE TODO #### */ // (void) VOP_PUTPAGE(vf->vf_vnode, 0, 0, B_INVAL, kcred); (void) vnode_close(vf->vf_vnode, spa_mode, context); (void) vfs_context_rele(context); #else (void) VOP_PUTPAGE(vf->vf_vnode, 0, 0, B_INVAL, kcred); (void) VOP_CLOSE(vf->vf_vnode, spa_mode, 1, 0, kcred); VN_RELE(vf->vf_vnode); #endif } kmem_free(vf, sizeof (vdev_file_t)); vd->vdev_tsd = NULL; }
static int vdev_file_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize, uint64_t *ashift) { vdev_file_t *vf; vnode_t *vp; vattr_t vattr; int error = 0; vnode_t *rootdir; /* * 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); } /* * Reopen the device if it's not currently open. Otherwise, * just update the physical size of the device. */ if (vd->vdev_tsd != NULL) { ASSERT(vd->vdev_reopening); vf = vd->vdev_tsd; vnode_getwithvid(vf->vf_vnode, vf->vf_vid); goto skip_open; } vf = vd->vdev_tsd = kmem_zalloc(sizeof (vdev_file_t), KM_PUSHPAGE); /* * We always open the files from the root of the global zone, even if * we're in a local zone. If the user has gotten to this point, the * administrator has already decided that the pool should be available * to local zone users, so the underlying devices should be as well. */ ASSERT(vd->vdev_path != NULL && vd->vdev_path[0] == '/'); /* vn_openat(char *pnamep, enum uio_seg seg, int filemode, int createmode, struct vnode **vpp, enum create crwhy, mode_t umask, struct vnode *startvp) extern int vn_openat(char *pnamep, enum uio_seg seg, int filemode, int createmode, struct vnode **vpp, enum create crwhy, mode_t umask, struct vnode *startvp); */ rootdir = getrootdir(); error = vn_openat(vd->vdev_path + 1, UIO_SYSSPACE, spa_mode(vd->vdev_spa) | FOFFMAX, 0, &vp, 0, 0, rootdir ); if (error) { vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; return (error); } vf->vf_vnode = vp; vf->vf_vid = vnode_vid(vp); #ifdef _KERNEL /* * Make sure it's a regular file. */ if (!vnode_isreg(vp)) { vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; vnode_put(vf->vf_vnode); return (ENODEV); } #endif skip_open: /* * Determine the physical size of the file. */ vattr.va_mask = AT_SIZE; error = VOP_GETATTR(vf->vf_vnode, &vattr, 0, kcred, NULL); if (error) { vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; vnode_put(vf->vf_vnode); return (error); } *max_psize = *psize = vattr.va_size; *ashift = SPA_MINBLOCKSHIFT; vnode_put(vf->vf_vnode); return (0); }
static int vdev_file_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize, uint64_t *ashift) { #if _KERNEL static vattr_t vattr; #endif vdev_file_t *vf; struct vnode *vp; int error = 0; struct vnode *rootdir; dprintf("vdev_file_open %p\n", vd->vdev_tsd); /* Rotational optimizations only make sense on block devices */ vd->vdev_nonrot = B_TRUE; /* * 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. */ #ifdef _KERNEL if (vd->vdev_tsd != NULL) { ASSERT(vd->vdev_reopening); vf = vd->vdev_tsd; vnode_getwithvid(vf->vf_vnode, vf->vf_vid); dprintf("skip to open\n"); goto skip_open; } #endif vf = vd->vdev_tsd = kmem_zalloc(sizeof (vdev_file_t), KM_SLEEP); /* * We always open the files from the root of the global zone, even if * we're in a local zone. If the user has gotten to this point, the * administrator has already decided that the pool should be available * to local zone users, so the underlying devices should be as well. */ ASSERT(vd->vdev_path != NULL && vd->vdev_path[0] == '/'); /* vn_openat(char *pnamep, enum uio_seg seg, int filemode, int createmode, struct vnode **vpp, enum create crwhy, mode_t umask, struct vnode *startvp) extern int vn_openat(char *pnamep, enum uio_seg seg, int filemode, int createmode, struct vnode **vpp, enum create crwhy, mode_t umask, struct vnode *startvp); */ rootdir = getrootdir(); error = vn_openat(vd->vdev_path + 1, UIO_SYSSPACE, spa_mode(vd->vdev_spa) | FOFFMAX, 0, &vp, 0, 0, rootdir ); if (error) { vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; return (error); } vf->vf_vnode = vp; #ifdef _KERNEL vf->vf_vid = vnode_vid(vp); dprintf("assigning vid %d\n", vf->vf_vid); /* * Make sure it's a regular file. */ if (!vnode_isreg(vp)) { vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; VN_RELE(vf->vf_vnode); return (SET_ERROR(ENODEV)); } #endif #if _KERNEL skip_open: /* * Determine the physical size of the file. */ vattr.va_mask = AT_SIZE; vn_lock(vf->vf_vnode, LK_SHARED | LK_RETRY); error = VOP_GETATTR(vf->vf_vnode, &vattr, 0, kcred, NULL); VN_UNLOCK(vf->vf_vnode); #endif if (error) { vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; VN_RELE(vf->vf_vnode); return (error); } #ifdef _KERNEL *max_psize = *psize = vattr.va_size; #else /* userland's vn_open() will get the device size for us, so we can * just look it up - there is argument for a userland VOP_GETATTR to make * this function cleaner. */ *max_psize = *psize = vp->v_size; #endif *ashift = SPA_MINBLOCKSHIFT; VN_RELE(vf->vf_vnode); return (0); }