/* * kobj_load_file: * * Load an object located in the file system. */ int kobj_load_file(kobj_t *kop, const char *filename, const char *base, bool autoload) { struct nameidata nd; kauth_cred_t cred; char *path; int error; kobj_t ko; cred = kauth_cred_get(); ko = kmem_zalloc(sizeof(*ko), KM_SLEEP); if (ko == NULL) { return ENOMEM; } if (autoload) { error = ENOENT; } else { NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename); error = vn_open(&nd, FREAD, 0); } if (error != 0) { if (error != ENOENT) { goto out; } path = PNBUF_GET(); snprintf(path, MAXPATHLEN - 1, "%s/%s/%s.kmod", base, filename, filename); NDINIT(&nd, LOOKUP, FOLLOW | NOCHROOT, UIO_SYSSPACE, path); error = vn_open(&nd, FREAD, 0); if (error != 0) { strlcat(path, ".o", MAXPATHLEN); NDINIT(&nd, LOOKUP, FOLLOW | NOCHROOT, UIO_SYSSPACE, path); error = vn_open(&nd, FREAD, 0); } PNBUF_PUT(path); if (error != 0) { goto out; } } out: if (error != 0) { kmem_free(ko, sizeof(*ko)); return error; } ko->ko_type = KT_VNODE; ko->ko_source = nd.ni_vp; *kop = ko; return kobj_load(ko); }
static int vfs_mountroot_readconf(struct thread *td, struct sbuf *sb) { static char buf[128]; struct nameidata nd; off_t ofs; ssize_t resid; int error, flags, len; NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, "/.mount.conf", td); flags = FREAD; error = vn_open(&nd, &flags, 0, NULL); if (error) return (error); NDFREE(&nd, NDF_ONLY_PNBUF); ofs = 0; len = sizeof(buf) - 1; while (1) { error = vn_rdwr(UIO_READ, nd.ni_vp, buf, len, ofs, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, &resid, td); if (error) break; if (resid == len) break; buf[len - resid] = 0; sbuf_printf(sb, "%s", buf); ofs += len - resid; } VOP_UNLOCK(nd.ni_vp, 0); vn_close(nd.ni_vp, FREAD, td->td_ucred, td); return (error); }
int randomdev_write_file(const char *filename, void *buf, size_t length) { struct nameidata nd; struct thread* td = curthread; int error; ssize_t resid; int flags; NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, td); flags = FWRITE | O_CREAT | O_TRUNC; error = vn_open(&nd, &flags, 0, NULL); if (error == 0) { NDFREE(&nd, NDF_ONLY_PNBUF); if (nd.ni_vp->v_type != VREG) error = ENOEXEC; else error = vn_rdwr(UIO_WRITE, nd.ni_vp, buf, length, 0, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, &resid, td); VOP_UNLOCK(nd.ni_vp, 0); vn_close(nd.ni_vp, FREAD, td->td_ucred, td); } return (error); }
/* * fp_open: * * Open a file as specified. Use O_* flags for flags. * * vn_open() asserts that the cred must match the process's cred. * * NOTE! when fp_open() is called from a pure thread, root creds are * used. */ int fp_open(const char *path, int flags, int mode, file_t *fpp) { struct nlookupdata nd; struct thread *td; struct file *fp; int error; if ((error = falloc(NULL, fpp, NULL)) != 0) return (error); fp = *fpp; td = curthread; if (td->td_proc) fsetcred(fp, td->td_proc->p_ucred); error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_LOCKVP); flags = FFLAGS(flags); if (error == 0) error = vn_open(&nd, fp, flags, mode); nlookup_done(&nd); if (error) { fdrop(fp); *fpp = NULL; } return(error); }
static int swap_file_open(struct chip_swap *swap, const char *swap_file) { struct nameidata nd; int flags, error; NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, swap_file, curthread); flags = FWRITE | FREAD | O_NOFOLLOW | O_CREAT | O_TRUNC; error = vn_open(&nd, &flags, CHIP_SWAP_CMODE, NULL); if (error) { nand_debug(NDBG_SIM,"Cannot create swap file %s", swap_file); NDFREE(&nd, NDF_ONLY_PNBUF); return (error); } swap->swap_cred = crhold(curthread->td_ucred); NDFREE(&nd, NDF_ONLY_PNBUF); /* We just unlock so we hold a reference */ VOP_UNLOCK(nd.ni_vp, 0); swap->swap_vp = nd.ni_vp; return (0); }
static int kfcreate(char *filename, kfile_t **kfilep) { kfile_t *fp; int rval; ASSERT(modrootloaded); fp = kmem_alloc(sizeof (kfile_t), KM_SLEEP); fp->kf_vnflags = FCREAT | FWRITE | FTRUNC; fp->kf_fname = filename; fp->kf_fpos = 0; fp->kf_state = 0; KFDEBUG((CE_CONT, "create: %s flags 0x%x\n", filename, fp->kf_vnflags)); rval = vn_open(filename, UIO_SYSSPACE, fp->kf_vnflags, 0444, &fp->kf_vp, CRCREAT, 0); if (rval != 0) { kmem_free(fp, sizeof (kfile_t)); KFDEBUG((CE_CONT, "%s: create error %d\n", filename, rval)); return (rval); } *kfilep = fp; return (0); }
static int splat_vnode_test1(struct file *file, void *arg) { vnode_t *vp; int rc; if ((rc = vn_open(SPLAT_VNODE_TEST_FILE, UIO_SYSSPACE, FREAD, 0644, &vp, 0, 0))) { splat_vprint(file, SPLAT_VNODE_TEST1_NAME, "Failed to vn_open test file: %s (%d)\n", SPLAT_VNODE_TEST_FILE, rc); return -rc; } rc = VOP_CLOSE(vp, 0, 0, 0, 0, 0); if (rc) { splat_vprint(file, SPLAT_VNODE_TEST1_NAME, "Failed to vn_close test file: %s (%d)\n", SPLAT_VNODE_TEST_FILE, rc); return -rc; } splat_vprint(file, SPLAT_VNODE_TEST1_NAME, "Successfully vn_open'ed " "and vn_closed test file: %s\n", SPLAT_VNODE_TEST_FILE); return -rc; } /* splat_vnode_test1() */
static int splat_vnode_test3(struct file *file, void *arg) { vnode_t *vp; char buf1[32] = "SPL VNode Interface Test File\n"; char buf2[32] = ""; int rc; if ((rc = splat_vnode_unlink_all(file, arg, SPLAT_VNODE_TEST3_NAME))) return rc; if ((rc = vn_open(SPLAT_VNODE_TEST_FILE_RW, UIO_SYSSPACE, FWRITE | FREAD | FCREAT | FEXCL, 0644, &vp, 0, 0))) { splat_vprint(file, SPLAT_VNODE_TEST3_NAME, "Failed to vn_open test file: %s (%d)\n", SPLAT_VNODE_TEST_FILE_RW, rc); return -rc; } rc = vn_rdwr(UIO_WRITE, vp, buf1, strlen(buf1), 0, UIO_SYSSPACE, 0, RLIM64_INFINITY, 0, NULL); if (rc) { splat_vprint(file, SPLAT_VNODE_TEST3_NAME, "Failed vn_rdwr write of test file: %s (%d)\n", SPLAT_VNODE_TEST_FILE_RW, rc); goto out; } rc = vn_rdwr(UIO_READ, vp, buf2, strlen(buf1), 0, UIO_SYSSPACE, 0, RLIM64_INFINITY, 0, NULL); if (rc) { splat_vprint(file, SPLAT_VNODE_TEST3_NAME, "Failed vn_rdwr read of test file: %s (%d)\n", SPLAT_VNODE_TEST_FILE_RW, rc); goto out; } if (strncmp(buf1, buf2, strlen(buf1))) { rc = EINVAL; splat_vprint(file, SPLAT_VNODE_TEST3_NAME, "Failed strncmp data written does not match " "data read\nWrote: %sRead: %s\n", buf1, buf2); goto out; } rc = 0; splat_vprint(file, SPLAT_VNODE_TEST3_NAME, "Wrote: %s", buf1); splat_vprint(file, SPLAT_VNODE_TEST3_NAME, "Read: %s", buf2); splat_vprint(file, SPLAT_VNODE_TEST3_NAME, "Successfully wrote and " "read expected data pattern to test file: %s\n", SPLAT_VNODE_TEST_FILE_RW); out: VOP_CLOSE(vp, 0, 0, 0, 0, 0); vn_remove(SPLAT_VNODE_TEST_FILE_RW, UIO_SYSSPACE, RMFILE); return -rc; } /* splat_vnode_test3() */
void vdsp_open(void *arg1, void *arg2) { struct vdsp_softc *sc = arg1; struct proc *p = curproc; struct vd_attr_info ai; if (sc->sc_vp == NULL) { struct nameidata nd; struct vattr va; const char *name; int error; name = mdesc_get_prop_str(sc->sc_idx, "vds-block-device"); if (name == NULL) return; NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, name, p); error = vn_open(&nd, FREAD | FWRITE, 0); if (error) { printf("VOP_OPEN: %s, %d\n", name, error); return; } error = VOP_GETATTR(nd.ni_vp, &va, p->p_ucred, p); if (error) printf("VOP_GETATTR: %s, %d\n", name, error); sc->sc_vdisk_block_size = DEV_BSIZE; sc->sc_vdisk_size = va.va_size / DEV_BSIZE; VOP_UNLOCK(nd.ni_vp, 0, p); sc->sc_vp = nd.ni_vp; vdsp_readlabel(sc); } bzero(&ai, sizeof(ai)); ai.tag.type = VIO_TYPE_CTRL; ai.tag.stype = VIO_SUBTYPE_ACK; ai.tag.stype_env = VIO_ATTR_INFO; ai.tag.sid = sc->sc_local_sid; ai.xfer_mode = sc->sc_xfer_mode; ai.vd_type = VD_DISK_TYPE_DISK; if (sc->sc_major > 1 || sc->sc_minor >= 1) { if (vdsp_is_iso(sc)) ai.vd_mtype = VD_MEDIA_TYPE_CD; else ai.vd_mtype = VD_MEDIA_TYPE_FIXED; } ai.vdisk_block_size = sc->sc_vdisk_block_size; ai.operations = VD_OP_MASK; ai.vdisk_size = sc->sc_vdisk_size; ai.max_xfer_sz = MAXPHYS / sc->sc_vdisk_block_size; vdsp_sendmsg(sc, &ai, sizeof(ai), 1); }
/* * Accounting system call. Written based on the specification and * previous implementation done by Mark Tinguely. */ int sys_acct(struct proc *p, void *v, register_t *retval) { struct sys_acct_args /* { syscallarg(const char *) path; } */ *uap = v; struct nameidata nd; int error; /* Make sure that the caller is root. */ if ((error = suser(p, 0)) != 0) return (error); /* * If accounting is to be started to a file, open that file for * writing and make sure it's 'normal'. */ if (SCARG(uap, path) != NULL) { NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p); if ((error = vn_open(&nd, FWRITE|O_APPEND, 0)) != 0) return (error); VOP_UNLOCK(nd.ni_vp, 0); if (nd.ni_vp->v_type != VREG) { vn_close(nd.ni_vp, FWRITE, p->p_ucred, p); return (EACCES); } } /* * If accounting was previously enabled, kill the old space-watcher, * close the file, and (if no new file was specified, leave). */ if (acctp != NULL || savacctp != NULL) { wakeup(&acct_proc); error = vn_close((acctp != NULL ? acctp : savacctp), FWRITE, p->p_ucred, p); acctp = savacctp = NULL; } if (SCARG(uap, path) == NULL) return (0); /* * Save the new accounting file vnode, and schedule the new * free space watcher. */ acctp = nd.ni_vp; if ((error = acct_start()) != 0) { acctp = NULL; (void)vn_close(nd.ni_vp, FWRITE, p->p_ucred, p); return (error); } return (0); }
static int spa_config_write(spa_config_dirent_t *dp, nvlist_t *nvl) { size_t buflen; char *buf; vnode_t *vp; int oflags = FWRITE | FTRUNC | FCREAT | FOFFMAX; char *temp; int err; /* * If the nvlist is empty (NULL), then remove the old cachefile. */ if (nvl == NULL) { err = vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE); return (err); } /* * Pack the configuration into a buffer. */ VERIFY(nvlist_size(nvl, &buflen, NV_ENCODE_XDR) == 0); buf = kmem_alloc(buflen, KM_SLEEP); temp = kmem_zalloc(MAXPATHLEN, KM_SLEEP); VERIFY(nvlist_pack(nvl, &buf, &buflen, NV_ENCODE_XDR, KM_SLEEP) == 0); /* * Write the configuration to disk. We need to do the traditional * 'write to temporary file, sync, move over original' to make sure we * always have a consistent view of the data. */ (void) snprintf(temp, MAXPATHLEN, "%s.tmp", dp->scd_path); err = vn_open(temp, UIO_SYSSPACE, oflags, 0644, &vp, CRCREAT, 0); if (err == 0) { err = vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, NULL); if (err == 0) err = VOP_FSYNC(vp, FSYNC, kcred, NULL); if (err == 0) err = vn_rename(temp, dp->scd_path, UIO_SYSSPACE); (void) VOP_CLOSE(vp, oflags, 1, 0, kcred, NULL); } (void) vn_remove(temp, UIO_SYSSPACE, RMFILE); kmem_free(buf, buflen); kmem_free(temp, MAXPATHLEN); return (err); }
static int vniocattach_shadow(struct vn_softc *vn, struct vn_ioctl_64 *vniop, __unused dev_t dev, int in_kernel, proc_t p) { vfs_context_t ctx = vfs_context_current(); struct nameidata nd; int error, flags; shadow_map_t * map; off_t file_size; flags = FREAD|FWRITE; if (in_kernel) { NDINIT(&nd, LOOKUP, OP_OPEN, FOLLOW, UIO_SYSSPACE, vniop->vn_file, ctx); } else { NDINIT(&nd, LOOKUP, OP_OPEN, FOLLOW, (IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32), vniop->vn_file, ctx); } /* vn_open gives both long- and short-term references */ error = vn_open(&nd, flags, 0); if (error) { /* shadow MUST be writable! */ return (error); } if (nd.ni_vp->v_type != VREG || (error = vnode_size(nd.ni_vp, &file_size, ctx))) { (void)vn_close(nd.ni_vp, flags, ctx); vnode_put(nd.ni_vp); return (error ? error : EINVAL); } map = shadow_map_create(vn->sc_fsize, file_size, 0, vn->sc_secsize); if (map == NULL) { (void)vn_close(nd.ni_vp, flags, ctx); vnode_put(nd.ni_vp); vn->sc_shadow_vp = NULL; return (ENOMEM); } vn->sc_shadow_vp = nd.ni_vp; vn->sc_shadow_vid = vnode_vid(nd.ni_vp); vn->sc_shadow_vp->v_flag |= VNOCACHE_DATA; vn->sc_shadow_map = map; vn->sc_flags &= ~VNF_READONLY; /* we're now read/write */ /* lose the short-term reference */ vnode_put(nd.ni_vp); return(0); }
char * linker_search_path(const char *name) { struct nameidata nd; struct proc *p = curproc; /* XXX */ char *cp, *ep, *result; int error; enum vtype type; /* qualified at all? */ if (index(name, '/')) return(linker_strdup(name)); /* traverse the linker path */ cp = linker_path; for (;;) { /* find the end of this component */ for (ep = cp; (*ep != 0) && (*ep != ';'); ep++) ; result = malloc((strlen(name) + (ep - cp) + 1), M_LINKER, M_WAITOK); if (result == NULL) /* actually ENOMEM */ return(NULL); strncpy(result, cp, ep - cp); strcpy(result + (ep - cp), name); /* * Attempt to open the file, and return the path if we succeed and it's * a regular file. */ NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, result, p); error = vn_open(&nd, FREAD, 0); if (error == 0) { type = nd.ni_vp->v_type; VOP_UNLOCK(nd.ni_vp, 0, p); vn_close(nd.ni_vp, FREAD, p->p_ucred, p); if (type == VREG) return(result); } free(result, M_LINKER); if (*ep == 0) break; cp = ep + 1; } return(NULL); }
/* * Lookup the provided name in the filesystem. If the file exists, * is a valid block device, and isn't being used by anyone else, * set *vpp to the file's vnode. */ int dk_lookup(struct pathbuf *pb, struct lwp *l, struct vnode **vpp) { struct nameidata nd; struct vnode *vp; int error; if (l == NULL) return ESRCH; /* Is ESRCH the best choice? */ NDINIT(&nd, LOOKUP, FOLLOW, pb); if ((error = vn_open(&nd, FREAD | FWRITE, 0)) != 0) { DPRINTF((DKDB_FOLLOW|DKDB_INIT), ("%s: vn_open error = %d\n", __func__, error)); return error; } vp = nd.ni_vp; if (vp->v_type != VBLK) { error = ENOTBLK; goto out; } /* Reopen as anonymous vnode to protect against forced unmount. */ if ((error = bdevvp(vp->v_rdev, vpp)) != 0) goto out; VOP_UNLOCK(vp); if ((error = vn_close(vp, FREAD | FWRITE, l->l_cred)) != 0) { vrele(*vpp); return error; } if ((error = VOP_OPEN(*vpp, FREAD | FWRITE, l->l_cred)) != 0) { vrele(*vpp); return error; } mutex_enter((*vpp)->v_interlock); (*vpp)->v_writecount++; mutex_exit((*vpp)->v_interlock); IFDEBUG(DKDB_VNODE, vprint("dk_lookup: vnode info", *vpp)); return 0; out: VOP_UNLOCK(vp); (void) vn_close(vp, FREAD | FWRITE, l->l_cred); return error; }
int vn_openat(char *path, enum uio_seg x1, int flags, int mode, vnode_t **vpp, enum create x2, mode_t x3, vnode_t *startvp, int fd) { char *realpath = kmem_alloc(strlen(path) + 2, KM_SLEEP); int ret; ASSERT(startvp == rootdir); (void) sprintf(realpath, "/%s", path); /* fd ignored for now, need if want to simulate nbmand support */ ret = vn_open(realpath, x1, flags, mode, vpp, x2, x3); kmem_free(realpath, strlen(path) + 2); return (ret); }
/* * Lookup the provided name in the filesystem. If the file exists, * is a valid block device, and isn't being used by anyone else, * set *vpp to the file's vnode. */ int ccdlookup(char *path, struct proc *p, struct vnode **vpp) { struct nameidata nd; struct vnode *vp; struct vattr va; int error; NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, p); if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) { CCD_DPRINTF(CCDB_FOLLOW | CCDB_INIT, ("ccdlookup: vn_open error = %d\n", error)); return (error); } vp = nd.ni_vp; if (vp->v_usecount > 1) { VOP_UNLOCK(vp, 0, p); (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); return (EBUSY); } if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0) { CCD_DPRINTF(CCDB_FOLLOW | CCDB_INIT, ("ccdlookup: getattr error = %d\n", error)); VOP_UNLOCK(vp, 0, p); (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); return (error); } /* XXX: eventually we should handle VREG, too. */ if (va.va_type != VBLK) { VOP_UNLOCK(vp, 0, p); (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); return (ENOTBLK); } #ifdef DIAGNOSTIC CCD_DCALL(CCDB_VNODE, vprint("ccdlookup: vnode info", vp)); #endif VOP_UNLOCK(vp, 0, p); *vpp = vp; return (0); }
cfs_file_t * kern_file_open(const char * filename, int flags, int mode, int *err) { struct nameidata nd; cfs_file_t *fp; register struct vnode *vp; int rc; extern struct fileops vnops; extern int nfiles; CFS_DECL_CONE_DATA; CFS_CONE_IN; nfiles++; MALLOC_ZONE(fp, cfs_file_t *, sizeof(cfs_file_t), M_FILE, M_WAITOK|M_ZERO); bzero(fp, sizeof(cfs_file_t)); fp->f_count = 1; LIST_CIRCLE(fp, f_list); NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, (char *)filename, current_proc()); if ((rc = vn_open(&nd, flags, mode)) != 0){ printf("filp_open failed at (%d)\n", rc); if (err != NULL) *err = rc; FREE_ZONE(fp, sizeof *fp, M_FILE); CFS_CONE_EX; return NULL; } vp = nd.ni_vp; fp->f_flag = flags & FMASK; fp->f_type = DTYPE_VNODE; fp->f_ops = &vnops; fp->f_data = (caddr_t)vp; fp->f_cred = current_proc()->p_ucred; /* * Hold cred to increase reference */ crhold(fp->f_cred); /* * vnode is locked inside vn_open for lookup, * we should release the lock before return */ VOP_UNLOCK(vp, 0, current_proc()); CFS_CONE_EX; return fp; }
/* * kobj_load_vfs: * * Load an object located in the file system. */ int kobj_load_vfs(kobj_t *kop, const char *path, const bool nochroot) { struct nameidata nd; struct pathbuf *pb; kauth_cred_t cred; int error; kobj_t ko; KASSERT(path != NULL); if (strchr(path, '/') == NULL) return ENOENT; cred = kauth_cred_get(); ko = kmem_zalloc(sizeof(*ko), KM_SLEEP); if (ko == NULL) { return ENOMEM; } pb = pathbuf_create(path); if (pb == NULL) { kmem_free(ko, sizeof(*ko)); return ENOMEM; } NDINIT(&nd, LOOKUP, FOLLOW | (nochroot ? NOCHROOT : 0), pb); error = vn_open(&nd, FREAD, 0); if (error != 0) { pathbuf_destroy(pb); kmem_free(ko, sizeof(*ko)); return error; } ko->ko_type = KT_VNODE; kobj_setname(ko, path); ko->ko_source = nd.ni_vp; ko->ko_read = kobj_read_vfs; ko->ko_close = kobj_close_vfs; pathbuf_destroy(pb); *kop = ko; return kobj_load(ko); }
static int splat_vnode_test6(struct file *file, void *arg) { vnode_t *vp; char buf[32] = "SPL VNode Interface Test File\n"; int rc; if ((rc = splat_vnode_unlink_all(file, arg, SPLAT_VNODE_TEST6_NAME))) return rc; if ((rc = vn_open(SPLAT_VNODE_TEST_FILE_RW, UIO_SYSSPACE, FWRITE | FCREAT | FEXCL, 0644, &vp, 0, 0))) { splat_vprint(file, SPLAT_VNODE_TEST6_NAME, "Failed to vn_open test file: %s (%d)\n", SPLAT_VNODE_TEST_FILE_RW, rc); return -rc; } rc = vn_rdwr(UIO_WRITE, vp, buf, strlen(buf), 0, UIO_SYSSPACE, 0, RLIM64_INFINITY, 0, NULL); if (rc) { splat_vprint(file, SPLAT_VNODE_TEST6_NAME, "Failed vn_rdwr write of test file: %s (%d)\n", SPLAT_VNODE_TEST_FILE_RW, rc); goto out; } rc = vn_fsync(vp, 0, 0, 0); if (rc) { splat_vprint(file, SPLAT_VNODE_TEST6_NAME, "Failed vn_fsync of test file: %s (%d)\n", SPLAT_VNODE_TEST_FILE_RW, rc); goto out; } rc = 0; splat_vprint(file, SPLAT_VNODE_TEST6_NAME, "Successfully " "fsync'ed test file %s\n", SPLAT_VNODE_TEST_FILE_RW); out: VOP_CLOSE(vp, 0, 0, 0, 0, 0); vn_remove(SPLAT_VNODE_TEST_FILE_RW, UIO_SYSSPACE, RMFILE); return -rc; } /* splat_vnode_test6() */
/* * Lookup the provided name in the filesystem. If the file exists, * is a valid block device, and isn't being used by anyone else, * set *vpp to the file's vnode. */ int dk_lookup(const char *path, struct lwp *l, struct vnode **vpp, enum uio_seg segflg) { struct nameidata nd; struct vnode *vp; struct vattr va; int error; if (l == NULL) return ESRCH; /* Is ESRCH the best choice? */ NDINIT(&nd, LOOKUP, FOLLOW, segflg, path); if ((error = vn_open(&nd, FREAD | FWRITE, 0)) != 0) { DPRINTF((DKDB_FOLLOW|DKDB_INIT), ("dk_lookup: vn_open error = %d\n", error)); return error; } vp = nd.ni_vp; if ((error = VOP_GETATTR(vp, &va, l->l_cred)) != 0) { DPRINTF((DKDB_FOLLOW|DKDB_INIT), ("dk_lookup: getattr error = %d\n", error)); goto out; } /* XXX: eventually we should handle VREG, too. */ if (va.va_type != VBLK) { error = ENOTBLK; goto out; } IFDEBUG(DKDB_VNODE, vprint("dk_lookup: vnode info", vp)); VOP_UNLOCK(vp, 0); *vpp = vp; return 0; out: VOP_UNLOCK(vp, 0); (void) vn_close(vp, FREAD | FWRITE, l->l_cred); return error; }
struct _buf * kobj_open_file(const char *name) { struct _buf *file; vnode_t *vp; int rc; file = kmalloc(sizeof(_buf_t), kmem_flags_convert(KM_SLEEP)); if (file == NULL) return ((_buf_t *)-1UL); if ((rc = vn_open(name, UIO_SYSSPACE, FREAD, 0644, &vp, 0, 0))) { kfree(file); return ((_buf_t *)-1UL); } file->vp = vp; return (file); } /* kobj_open_file() */
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) { char *path; int pathlen = MAXPATHLEN; int error; path = (char *)kmem_zalloc(MAXPATHLEN, KM_SLEEP); error = vn_getpath(startvp, path, &pathlen); if (error == 0) { strlcat(path, pnamep, MAXPATHLEN); error = vn_open(path, seg, filemode, createmode, vpp, crwhy, umask); } kmem_free(path, MAXPATHLEN); return (error); }
static int splat_vnode_test5(struct file *file, void *arg) { vnode_t *vp; vattr_t vap; int rc; if ((rc = vn_open(SPLAT_VNODE_TEST_FILE, UIO_SYSSPACE, FREAD, 0644, &vp, 0, 0))) { splat_vprint(file, SPLAT_VNODE_TEST5_NAME, "Failed to vn_open test file: %s (%d)\n", SPLAT_VNODE_TEST_FILE, rc); return -rc; } rc = VOP_GETATTR(vp, &vap, 0, 0, NULL); if (rc) { splat_vprint(file, SPLAT_VNODE_TEST5_NAME, "Failed to vn_getattr test file: %s (%d)\n", SPLAT_VNODE_TEST_FILE, rc); goto out; } if (vap.va_type != VREG) { rc = EINVAL; splat_vprint(file, SPLAT_VNODE_TEST5_NAME, "Failed expected regular file type " "(%d != VREG): %s (%d)\n", vap.va_type, SPLAT_VNODE_TEST_FILE, rc); goto out; } splat_vprint(file, SPLAT_VNODE_TEST1_NAME, "Successfully " "vn_getattr'ed test file: %s\n", SPLAT_VNODE_TEST_FILE); out: VOP_CLOSE(vp, 0, 0, 0, 0, 0); return -rc; } /* splat_vnode_test5() */
/* * reads config data into cprconfig */ static int cpr_get_config(void) { static char config_path[] = CPR_CONFIG; struct cprconfig *cf = &cprconfig; struct vnode *vp; char *fmt; int err; if (cprconfig_loaded) return (0); fmt = "cannot %s config file \"%s\", error %d\n"; if (err = vn_open(config_path, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0)) { cpr_err(CE_CONT, fmt, "open", config_path, err); return (err); } err = cpr_rdwr(UIO_READ, vp, cf, sizeof (*cf)); (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL); VN_RELE(vp); if (err) { cpr_err(CE_CONT, fmt, "read", config_path, err); return (err); } if (cf->cf_magic == CPR_CONFIG_MAGIC) cprconfig_loaded = 1; else { cpr_err(CE_CONT, "invalid config file \"%s\", " "rerun pmconfig(1M)\n", config_path); err = EINVAL; } return (err); }
/* ARGSUSED */ int auditctl(struct thread *td, struct auditctl_args *uap) { struct nameidata nd; struct ucred *cred; struct vnode *vp; int error = 0; int flags, vfslocked; if (jailed(td->td_ucred)) return (ENOSYS); error = priv_check(td, PRIV_AUDIT_CONTROL); if (error) return (error); vp = NULL; cred = NULL; /* * If a path is specified, open the replacement vnode, perform * validity checks, and grab another reference to the current * credential. * * On Darwin, a NULL path argument is also used to disable audit. */ if (uap->path == NULL) return (EINVAL); NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1, UIO_USERSPACE, uap->path, td); flags = AUDIT_OPEN_FLAGS; error = vn_open(&nd, &flags, 0, NULL); if (error) return (error); vfslocked = NDHASGIANT(&nd); vp = nd.ni_vp; #ifdef MAC error = mac_system_check_auditctl(td->td_ucred, vp); VOP_UNLOCK(vp, 0); if (error) { vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td); VFS_UNLOCK_GIANT(vfslocked); return (error); } #else VOP_UNLOCK(vp, 0); #endif NDFREE(&nd, NDF_ONLY_PNBUF); if (vp->v_type != VREG) { vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td); VFS_UNLOCK_GIANT(vfslocked); return (EINVAL); } VFS_UNLOCK_GIANT(vfslocked); cred = td->td_ucred; crhold(cred); /* * XXXAUDIT: Should audit_suspended actually be cleared by * audit_worker? */ audit_suspended = 0; audit_rotate_vnode(cred, vp); return (error); }
/* * Synchronize all pools to disk. This must be called with the namespace lock * held. */ void spa_config_sync(void) { spa_t *spa = NULL; nvlist_t *config; size_t buflen; char *buf; vnode_t *vp; int oflags = FWRITE | FTRUNC | FCREAT | FOFFMAX; char pathname[128]; char pathname2[128]; ASSERT(MUTEX_HELD(&spa_namespace_lock)); VERIFY(nvlist_alloc(&config, NV_UNIQUE_NAME, KM_SLEEP) == 0); /* * Add all known pools to the configuration list, ignoring those with * alternate root paths. */ spa = NULL; while ((spa = spa_next(spa)) != NULL) { mutex_enter(&spa->spa_config_cache_lock); if (spa->spa_config && spa->spa_name && spa->spa_root == NULL) VERIFY(nvlist_add_nvlist(config, spa->spa_name, spa->spa_config) == 0); mutex_exit(&spa->spa_config_cache_lock); } /* * Pack the configuration into a buffer. */ VERIFY(nvlist_size(config, &buflen, NV_ENCODE_XDR) == 0); buf = kmem_alloc(buflen, KM_SLEEP); VERIFY(nvlist_pack(config, &buf, &buflen, NV_ENCODE_XDR, KM_SLEEP) == 0); /* * Write the configuration to disk. We need to do the traditional * 'write to temporary file, sync, move over original' to make sure we * always have a consistent view of the data. */ (void) snprintf(pathname, sizeof (pathname), "%s/%s", spa_config_dir, ZPOOL_CACHE_TMP); if (vn_open(pathname, UIO_SYSSPACE, oflags, 0644, &vp, CRCREAT, 0) != 0) goto out; if (vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, NULL) == 0 && VOP_FSYNC(vp, FSYNC, kcred) == 0) { (void) snprintf(pathname2, sizeof (pathname2), "%s/%s", spa_config_dir, ZPOOL_CACHE_FILE); (void) vn_rename(pathname, pathname2, UIO_SYSSPACE); } (void) VOP_CLOSE(vp, oflags, 1, 0, kcred); VN_RELE(vp); out: (void) vn_remove(pathname, UIO_SYSSPACE, RMFILE); spa_config_generation++; kmem_free(buf, buflen); nvlist_free(config); }
static int link_elf_load_file(linker_class_t cls, const char *filename, linker_file_t *result) { struct nameidata nd; struct thread *td = curthread; /* XXX */ Elf_Ehdr *hdr; Elf_Shdr *shdr; Elf_Sym *es; int nbytes, i, j; vm_offset_t mapbase; size_t mapsize; int error = 0; ssize_t resid; int flags; elf_file_t ef; linker_file_t lf; int symtabindex; int symstrindex; int shstrindex; int nsym; int pb, rl, ra; int alignmask; shdr = NULL; lf = NULL; mapsize = 0; hdr = NULL; NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, td); flags = FREAD; error = vn_open(&nd, &flags, 0, NULL); if (error) return error; NDFREE(&nd, NDF_ONLY_PNBUF); if (nd.ni_vp->v_type != VREG) { error = ENOEXEC; goto out; } #ifdef MAC error = mac_kld_check_load(td->td_ucred, nd.ni_vp); if (error) { goto out; } #endif /* Read the elf header from the file. */ hdr = malloc(sizeof(*hdr), M_LINKER, M_WAITOK); error = vn_rdwr(UIO_READ, nd.ni_vp, (void *)hdr, sizeof(*hdr), 0, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, &resid, td); if (error) goto out; if (resid != 0){ error = ENOEXEC; goto out; } if (!IS_ELF(*hdr)) { error = ENOEXEC; goto out; } if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || hdr->e_ident[EI_DATA] != ELF_TARG_DATA) { link_elf_error(filename, "Unsupported file layout"); error = ENOEXEC; goto out; } if (hdr->e_ident[EI_VERSION] != EV_CURRENT || hdr->e_version != EV_CURRENT) { link_elf_error(filename, "Unsupported file version"); error = ENOEXEC; goto out; } if (hdr->e_type != ET_REL) { error = ENOSYS; goto out; } if (hdr->e_machine != ELF_TARG_MACH) { link_elf_error(filename, "Unsupported machine"); error = ENOEXEC; goto out; } lf = linker_make_file(filename, &link_elf_class); if (!lf) { error = ENOMEM; goto out; } ef = (elf_file_t) lf; ef->nprogtab = 0; ef->e_shdr = 0; ef->nreltab = 0; ef->nrelatab = 0; /* Allocate and read in the section header */ nbytes = hdr->e_shnum * hdr->e_shentsize; if (nbytes == 0 || hdr->e_shoff == 0 || hdr->e_shentsize != sizeof(Elf_Shdr)) { error = ENOEXEC; goto out; } shdr = malloc(nbytes, M_LINKER, M_WAITOK); ef->e_shdr = shdr; error = vn_rdwr(UIO_READ, nd.ni_vp, (caddr_t)shdr, nbytes, hdr->e_shoff, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, &resid, td); if (error) goto out; if (resid) { error = ENOEXEC; goto out; } /* Scan the section header for information and table sizing. */ nsym = 0; symtabindex = -1; symstrindex = -1; for (i = 0; i < hdr->e_shnum; i++) { if (shdr[i].sh_size == 0) continue; switch (shdr[i].sh_type) { case SHT_PROGBITS: case SHT_NOBITS: ef->nprogtab++; break; case SHT_SYMTAB: nsym++; symtabindex = i; symstrindex = shdr[i].sh_link; break; case SHT_REL: ef->nreltab++; break; case SHT_RELA: ef->nrelatab++; break; case SHT_STRTAB: break; } } if (ef->nprogtab == 0) { link_elf_error(filename, "file has no contents"); error = ENOEXEC; goto out; } if (nsym != 1) { /* Only allow one symbol table for now */ link_elf_error(filename, "file has no valid symbol table"); error = ENOEXEC; goto out; } if (symstrindex < 0 || symstrindex > hdr->e_shnum || shdr[symstrindex].sh_type != SHT_STRTAB) { link_elf_error(filename, "file has invalid symbol strings"); error = ENOEXEC; goto out; } /* Allocate space for tracking the load chunks */ if (ef->nprogtab != 0) ef->progtab = malloc(ef->nprogtab * sizeof(*ef->progtab), M_LINKER, M_WAITOK | M_ZERO); if (ef->nreltab != 0) ef->reltab = malloc(ef->nreltab * sizeof(*ef->reltab), M_LINKER, M_WAITOK | M_ZERO); if (ef->nrelatab != 0) ef->relatab = malloc(ef->nrelatab * sizeof(*ef->relatab), M_LINKER, M_WAITOK | M_ZERO); if (symtabindex == -1) panic("lost symbol table index"); /* Allocate space for and load the symbol table */ ef->ddbsymcnt = shdr[symtabindex].sh_size / sizeof(Elf_Sym); ef->ddbsymtab = malloc(shdr[symtabindex].sh_size, M_LINKER, M_WAITOK); error = vn_rdwr(UIO_READ, nd.ni_vp, (void *)ef->ddbsymtab, shdr[symtabindex].sh_size, shdr[symtabindex].sh_offset, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, &resid, td); if (error) goto out; if (resid != 0){ error = EINVAL; goto out; } if (symstrindex == -1) panic("lost symbol string index"); /* Allocate space for and load the symbol strings */ ef->ddbstrcnt = shdr[symstrindex].sh_size; ef->ddbstrtab = malloc(shdr[symstrindex].sh_size, M_LINKER, M_WAITOK); error = vn_rdwr(UIO_READ, nd.ni_vp, ef->ddbstrtab, shdr[symstrindex].sh_size, shdr[symstrindex].sh_offset, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, &resid, td); if (error) goto out; if (resid != 0){ error = EINVAL; goto out; } /* Do we have a string table for the section names? */ shstrindex = -1; if (hdr->e_shstrndx != 0 && shdr[hdr->e_shstrndx].sh_type == SHT_STRTAB) { shstrindex = hdr->e_shstrndx; ef->shstrcnt = shdr[shstrindex].sh_size; ef->shstrtab = malloc(shdr[shstrindex].sh_size, M_LINKER, M_WAITOK); error = vn_rdwr(UIO_READ, nd.ni_vp, ef->shstrtab, shdr[shstrindex].sh_size, shdr[shstrindex].sh_offset, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, &resid, td); if (error) goto out; if (resid != 0){ error = EINVAL; goto out; } } /* Size up code/data(progbits) and bss(nobits). */ alignmask = 0; for (i = 0; i < hdr->e_shnum; i++) { if (shdr[i].sh_size == 0) continue; switch (shdr[i].sh_type) { case SHT_PROGBITS: case SHT_NOBITS: alignmask = shdr[i].sh_addralign - 1; mapsize += alignmask; mapsize &= ~alignmask; mapsize += shdr[i].sh_size; break; } } /* * We know how much space we need for the text/data/bss/etc. * This stuff needs to be in a single chunk so that profiling etc * can get the bounds and gdb can associate offsets with modules */ ef->object = vm_object_allocate(OBJT_DEFAULT, round_page(mapsize) >> PAGE_SHIFT); if (ef->object == NULL) { error = ENOMEM; goto out; } ef->address = (caddr_t) vm_map_min(kernel_map); /* * In order to satisfy amd64's architectural requirements on the * location of code and data in the kernel's address space, request a * mapping that is above the kernel. */ #ifdef __amd64__ mapbase = KERNBASE; #else mapbase = VM_MIN_KERNEL_ADDRESS; #endif error = vm_map_find(kernel_map, ef->object, 0, &mapbase, round_page(mapsize), 0, VMFS_OPTIMAL_SPACE, VM_PROT_ALL, VM_PROT_ALL, 0); if (error) { vm_object_deallocate(ef->object); ef->object = 0; goto out; } /* Wire the pages */ error = vm_map_wire(kernel_map, mapbase, mapbase + round_page(mapsize), VM_MAP_WIRE_SYSTEM|VM_MAP_WIRE_NOHOLES); if (error != KERN_SUCCESS) { error = ENOMEM; goto out; } /* Inform the kld system about the situation */ lf->address = ef->address = (caddr_t)mapbase; lf->size = mapsize; /* * Now load code/data(progbits), zero bss(nobits), allocate space for * and load relocs */ pb = 0; rl = 0; ra = 0; alignmask = 0; for (i = 0; i < hdr->e_shnum; i++) { if (shdr[i].sh_size == 0) continue; switch (shdr[i].sh_type) { case SHT_PROGBITS: case SHT_NOBITS: alignmask = shdr[i].sh_addralign - 1; mapbase += alignmask; mapbase &= ~alignmask; if (ef->shstrtab && shdr[i].sh_name != 0) ef->progtab[pb].name = ef->shstrtab + shdr[i].sh_name; else if (shdr[i].sh_type == SHT_PROGBITS) ef->progtab[pb].name = "<<PROGBITS>>"; else ef->progtab[pb].name = "<<NOBITS>>"; if (ef->progtab[pb].name != NULL && !strcmp(ef->progtab[pb].name, DPCPU_SETNAME)) ef->progtab[pb].addr = dpcpu_alloc(shdr[i].sh_size); #ifdef VIMAGE else if (ef->progtab[pb].name != NULL && !strcmp(ef->progtab[pb].name, VNET_SETNAME)) ef->progtab[pb].addr = vnet_data_alloc(shdr[i].sh_size); #endif else ef->progtab[pb].addr = (void *)(uintptr_t)mapbase; if (ef->progtab[pb].addr == NULL) { error = ENOSPC; goto out; } ef->progtab[pb].size = shdr[i].sh_size; ef->progtab[pb].sec = i; if (shdr[i].sh_type == SHT_PROGBITS) { error = vn_rdwr(UIO_READ, nd.ni_vp, ef->progtab[pb].addr, shdr[i].sh_size, shdr[i].sh_offset, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, &resid, td); if (error) goto out; if (resid != 0){ error = EINVAL; goto out; } /* Initialize the per-cpu or vnet area. */ if (ef->progtab[pb].addr != (void *)mapbase && !strcmp(ef->progtab[pb].name, DPCPU_SETNAME)) dpcpu_copy(ef->progtab[pb].addr, shdr[i].sh_size); #ifdef VIMAGE else if (ef->progtab[pb].addr != (void *)mapbase && !strcmp(ef->progtab[pb].name, VNET_SETNAME)) vnet_data_copy(ef->progtab[pb].addr, shdr[i].sh_size); #endif } else bzero(ef->progtab[pb].addr, shdr[i].sh_size); /* Update all symbol values with the offset. */ for (j = 0; j < ef->ddbsymcnt; j++) { es = &ef->ddbsymtab[j]; if (es->st_shndx != i) continue; es->st_value += (Elf_Addr)ef->progtab[pb].addr; } mapbase += shdr[i].sh_size; pb++; break; case SHT_REL: ef->reltab[rl].rel = malloc(shdr[i].sh_size, M_LINKER, M_WAITOK); ef->reltab[rl].nrel = shdr[i].sh_size / sizeof(Elf_Rel); ef->reltab[rl].sec = shdr[i].sh_info; error = vn_rdwr(UIO_READ, nd.ni_vp, (void *)ef->reltab[rl].rel, shdr[i].sh_size, shdr[i].sh_offset, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, &resid, td); if (error) goto out; if (resid != 0){ error = EINVAL; goto out; } rl++; break; case SHT_RELA: ef->relatab[ra].rela = malloc(shdr[i].sh_size, M_LINKER, M_WAITOK); ef->relatab[ra].nrela = shdr[i].sh_size / sizeof(Elf_Rela); ef->relatab[ra].sec = shdr[i].sh_info; error = vn_rdwr(UIO_READ, nd.ni_vp, (void *)ef->relatab[ra].rela, shdr[i].sh_size, shdr[i].sh_offset, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, &resid, td); if (error) goto out; if (resid != 0){ error = EINVAL; goto out; } ra++; break; } } if (pb != ef->nprogtab) panic("lost progbits"); if (rl != ef->nreltab) panic("lost reltab"); if (ra != ef->nrelatab) panic("lost relatab"); if (mapbase != (vm_offset_t)ef->address + mapsize) panic("mapbase 0x%lx != address %p + mapsize 0x%lx (0x%lx)\n", (u_long)mapbase, ef->address, (u_long)mapsize, (u_long)(vm_offset_t)ef->address + mapsize); /* Local intra-module relocations */ link_elf_reloc_local(lf); /* Pull in dependencies */ VOP_UNLOCK(nd.ni_vp, 0); error = linker_load_dependencies(lf); vn_lock(nd.ni_vp, LK_EXCLUSIVE | LK_RETRY); if (error) goto out; /* External relocations */ error = relocate_file(ef); if (error) goto out; /* Notify MD code that a module is being loaded. */ error = elf_cpu_load_file(lf); if (error) goto out; *result = lf; out: VOP_UNLOCK(nd.ni_vp, 0); vn_close(nd.ni_vp, FREAD, td->td_ucred, td); if (error && lf) linker_file_unload(lf, LINKER_UNLOAD_FORCE); if (hdr) free(hdr, M_LINKER); return error; }
static int vniocattach_file(struct vn_softc *vn, struct vn_ioctl_64 *vniop, dev_t dev, int in_kernel, proc_t p) { dev_t cdev; vfs_context_t ctx = vfs_context_current(); kauth_cred_t cred; struct nameidata nd; off_t file_size; int error, flags; flags = FREAD|FWRITE; if (in_kernel) { NDINIT(&nd, LOOKUP, OP_OPEN, FOLLOW, UIO_SYSSPACE, vniop->vn_file, ctx); } else { NDINIT(&nd, LOOKUP, OP_OPEN, FOLLOW, (IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32), vniop->vn_file, ctx); } /* vn_open gives both long- and short-term references */ error = vn_open(&nd, flags, 0); if (error) { if (error != EACCES && error != EPERM && error != EROFS) { return (error); } flags &= ~FWRITE; if (in_kernel) { NDINIT(&nd, LOOKUP, OP_OPEN, FOLLOW, UIO_SYSSPACE, vniop->vn_file, ctx); } else { NDINIT(&nd, LOOKUP, OP_OPEN, FOLLOW, (IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32), vniop->vn_file, ctx); } error = vn_open(&nd, flags, 0); if (error) { return (error); } } if (nd.ni_vp->v_type != VREG) { error = EINVAL; } else { error = vnode_size(nd.ni_vp, &file_size, ctx); } if (error != 0) { (void) vn_close(nd.ni_vp, flags, ctx); vnode_put(nd.ni_vp); return (error); } cred = kauth_cred_proc_ref(p); nd.ni_vp->v_flag |= VNOCACHE_DATA; error = setcred(nd.ni_vp, cred); if (error) { (void)vn_close(nd.ni_vp, flags, ctx); vnode_put(nd.ni_vp); kauth_cred_unref(&cred); return(error); } vn->sc_secsize = DEV_BSIZE; vn->sc_fsize = file_size; vn->sc_size = file_size / vn->sc_secsize; vn->sc_vp = nd.ni_vp; vn->sc_vid = vnode_vid(nd.ni_vp); vn->sc_open_flags = flags; vn->sc_cred = cred; cdev = makedev(vndevice_cdev_major, minor(dev)); vn->sc_cdev = devfs_make_node(cdev, DEVFS_CHAR, UID_ROOT, GID_OPERATOR, 0600, "rvn%d", minor(dev)); vn->sc_flags |= VNF_INITED; if (flags == FREAD) vn->sc_flags |= VNF_READONLY; /* lose the short-term reference */ vnode_put(nd.ni_vp); return(0); }
/* * set up a quota file for a particular file system. */ int lfsquota1_handle_cmd_quotaon(struct lwp *l, struct ulfsmount *ump, int type, const char *fname) { struct mount *mp = ump->um_mountp; struct lfs *fs = ump->um_lfs; struct vnode *vp, **vpp; struct vnode_iterator *marker; struct dquot *dq; int error; struct pathbuf *pb; struct nameidata nd; if (fs->um_flags & ULFS_QUOTA2) { uprintf("%s: quotas v2 already enabled\n", mp->mnt_stat.f_mntonname); return (EBUSY); } vpp = &ump->um_quotas[type]; pb = pathbuf_create(fname); if (pb == NULL) { return ENOMEM; } NDINIT(&nd, LOOKUP, FOLLOW, pb); if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) { pathbuf_destroy(pb); return error; } vp = nd.ni_vp; pathbuf_destroy(pb); VOP_UNLOCK(vp); if (vp->v_type != VREG) { (void) vn_close(vp, FREAD|FWRITE, l->l_cred); return (EACCES); } if (*vpp != vp) lfsquota1_handle_cmd_quotaoff(l, ump, type); mutex_enter(&lfs_dqlock); while ((ump->umq1_qflags[type] & (QTF_CLOSING | QTF_OPENING)) != 0) cv_wait(&lfs_dqcv, &lfs_dqlock); ump->umq1_qflags[type] |= QTF_OPENING; mutex_exit(&lfs_dqlock); mp->mnt_flag |= MNT_QUOTA; vp->v_vflag |= VV_SYSTEM; /* XXXSMP */ *vpp = vp; /* * Save the credential of the process that turned on quotas. * Set up the time limits for this quota. */ kauth_cred_hold(l->l_cred); ump->um_cred[type] = l->l_cred; ump->umq1_btime[type] = MAX_DQ_TIME; ump->umq1_itime[type] = MAX_IQ_TIME; if (lfs_dqget(NULLVP, 0, ump, type, &dq) == 0) { if (dq->dq_btime > 0) ump->umq1_btime[type] = dq->dq_btime; if (dq->dq_itime > 0) ump->umq1_itime[type] = dq->dq_itime; lfs_dqrele(NULLVP, dq); } /* * Search vnodes associated with this mount point, * adding references to quota file being opened. * NB: only need to add dquot's for inodes being modified. */ vfs_vnode_iterator_init(mp, &marker); while ((vp = vfs_vnode_iterator_next(marker, NULL, NULL))) { error = vn_lock(vp, LK_EXCLUSIVE); if (error) { vrele(vp); continue; } mutex_enter(vp->v_interlock); if (VTOI(vp) == NULL || vp->v_type == VNON || vp->v_writecount == 0) { mutex_exit(vp->v_interlock); vput(vp); continue; } mutex_exit(vp->v_interlock); if ((error = lfs_getinoquota(VTOI(vp))) != 0) { vput(vp); break; } vput(vp); } vfs_vnode_iterator_destroy(marker); mutex_enter(&lfs_dqlock); ump->umq1_qflags[type] &= ~QTF_OPENING; cv_broadcast(&lfs_dqcv); if (error == 0) fs->um_flags |= ULFS_QUOTA; mutex_exit(&lfs_dqlock); if (error) lfsquota1_handle_cmd_quotaoff(l, ump, type); return (error); }
static void spa_config_write(spa_config_dirent_t *dp, nvlist_t *nvl) { size_t buflen; char *buf; vnode_t *vp; int oflags = FWRITE | FTRUNC | FCREAT | FOFFMAX; int error; char *temp; /* * If the nvlist is empty (NULL), then remove the old cachefile. */ if (nvl == NULL) { (void) vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE); return; } /* * Pack the configuration into a buffer. */ VERIFY(nvlist_size(nvl, &buflen, NV_ENCODE_XDR) == 0); buf = vmem_alloc(buflen, KM_SLEEP); temp = kmem_zalloc(MAXPATHLEN, KM_SLEEP); VERIFY(nvlist_pack(nvl, &buf, &buflen, NV_ENCODE_XDR, KM_SLEEP) == 0); #if defined(__linux__) && defined(_KERNEL) /* * Write the configuration to disk. Due to the complexity involved * in performing a rename from within the kernel the file is truncated * and overwritten in place. In the event of an error the file is * unlinked to make sure we always have a consistent view of the data. */ error = vn_open(dp->scd_path, UIO_SYSSPACE, oflags, 0644, &vp, 0, 0); if (error == 0) { error = vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, NULL); if (error == 0) error = VOP_FSYNC(vp, FSYNC, kcred, NULL); (void) VOP_CLOSE(vp, oflags, 1, 0, kcred, NULL); if (error) (void) vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE); } #else /* * Write the configuration to disk. We need to do the traditional * 'write to temporary file, sync, move over original' to make sure we * always have a consistent view of the data. */ (void) snprintf(temp, MAXPATHLEN, "%s.tmp", dp->scd_path); error = vn_open(temp, UIO_SYSSPACE, oflags, 0644, &vp, CRCREAT, 0); if (error == 0) { if (vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, NULL) == 0 && VOP_FSYNC(vp, FSYNC, kcred, NULL) == 0) { (void) vn_rename(temp, dp->scd_path, UIO_SYSSPACE); } (void) VOP_CLOSE(vp, oflags, 1, 0, kcred, NULL); } (void) vn_remove(temp, UIO_SYSSPACE, RMFILE); #endif vmem_free(buf, buflen); kmem_free(temp, MAXPATHLEN); }