/* * Add a ref to a vnode's existing VM object, return the object or * NULL if the vnode did not have one. This does not create the * object (we can't since we don't know what the proper blocksize/boff * is to match the VFS's use of the buffer cache). */ vm_object_t vnode_pager_reference(struct vnode *vp) { vm_object_t object; /* * Prevent race condition when allocating the object. This * can happen with NFS vnodes since the nfsnode isn't locked. * * Serialize potential vnode/object teardowns and interlocks */ lwkt_gettoken(&vp->v_token); while (vp->v_flag & VOLOCK) { vsetflags(vp, VOWANT); tsleep(vp, 0, "vnpobj", 0); } vsetflags(vp, VOLOCK); lwkt_reltoken(&vp->v_token); /* * Prevent race conditions against deallocation of the VM * object. */ while ((object = vp->v_object) != NULL) { vm_object_hold(object); if ((object->flags & OBJ_DEAD) == 0) break; vm_object_dead_sleep(object, "vadead"); vm_object_drop(object); } /* * The object is expected to exist, the caller will handle * NULL returns if it does not. */ if (object) { object->ref_count++; vref(vp); } lwkt_gettoken(&vp->v_token); vclrflags(vp, VOLOCK); if (vp->v_flag & VOWANT) { vclrflags(vp, VOWANT); wakeup(vp); } lwkt_reltoken(&vp->v_token); if (object) vm_object_drop(object); return (object); }
/* * This opens /dev/tty. Because multiple opens of /dev/tty only * generate a single open to the actual tty, the file modes are * locked to FREAD|FWRITE. */ static int cttyopen(struct dev_open_args *ap) { struct proc *p = curproc; struct vnode *ttyvp; int error; KKASSERT(p); retry: if ((ttyvp = cttyvp(p)) == NULL) return (ENXIO); if (ttyvp->v_flag & VCTTYISOPEN) return (0); /* * Messy interlock, don't let the vnode go away while we try to * lock it and check for race after we might have blocked. */ vhold(ttyvp); vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY); if (ttyvp != cttyvp(p) || (ttyvp->v_flag & VCTTYISOPEN)) { kprintf("Warning: cttyopen: race avoided\n"); vn_unlock(ttyvp); vdrop(ttyvp); goto retry; } vsetflags(ttyvp, VCTTYISOPEN); error = VOP_OPEN(ttyvp, FREAD|FWRITE, ap->a_cred, NULL); if (error) vclrflags(ttyvp, VCTTYISOPEN); vn_unlock(ttyvp); vdrop(ttyvp); return(error); }
/* * NOTE: VAGE is always cleared when calling VOP_OPEN(). */ int vop_open(struct vop_ops *ops, struct vnode *vp, int mode, struct ucred *cred, struct file *fp) { struct vop_open_args ap; VFS_MPLOCK_DECLARE; int error; /* * Decrement 3-2-1-0. Does not decrement beyond 0 */ if (vp->v_flag & VAGE0) { vclrflags(vp, VAGE0); } else if (vp->v_flag & VAGE1) { vclrflags(vp, VAGE1); vsetflags(vp, VAGE0); } ap.a_head.a_desc = &vop_open_desc; ap.a_head.a_ops = ops; ap.a_vp = vp; ap.a_fp = fp; ap.a_mode = mode; ap.a_cred = cred; VFS_MPLOCK1(vp->v_mount); DO_OPS(ops, error, &ap, vop_open); VFS_MPUNLOCK(vp->v_mount); return(error); }
/* * This opens /dev/tty. Because multiple opens of /dev/tty only * generate a single open to the actual tty, the file modes are * locked to FREAD|FWRITE. */ static int cttyopen(struct dev_open_args *ap) { struct proc *p = curproc; struct vnode *ttyvp; int error; KKASSERT(p); retry: if ((ttyvp = cttyvp(p)) == NULL) return (ENXIO); if (ttyvp->v_flag & VCTTYISOPEN) return (0); /* * Messy interlock, don't let the vnode go away while we try to * lock it and check for race after we might have blocked. * * WARNING! The device open (devfs_spec_open()) temporarily * releases the vnode lock on ttyvp when issuing the * dev_dopen(), which means that the VCTTYISOPEn flag * can race during the VOP_OPEN(). * * If something does race we have to undo our potentially * extra open. */ vhold(ttyvp); vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY); if (ttyvp != cttyvp(p) || (ttyvp->v_flag & VCTTYISOPEN)) { kprintf("Warning: cttyopen: race-1 avoided\n"); vn_unlock(ttyvp); vdrop(ttyvp); goto retry; } error = VOP_OPEN(ttyvp, FREAD|FWRITE, ap->a_cred, NULL); /* * Race against ctty close or change. This case has been validated * and occurs every so often during synth builds. */ if (ttyvp != cttyvp(p) || (ttyvp->v_flag & VCTTYISOPEN)) { if (error == 0) VOP_CLOSE(ttyvp, FREAD|FWRITE, NULL); vn_unlock(ttyvp); vdrop(ttyvp); goto retry; } if (error == 0) vsetflags(ttyvp, VCTTYISOPEN); vn_unlock(ttyvp); vdrop(ttyvp); return(error); }
void vsetobjdirty(struct vnode *vp) { struct syncer_ctx *ctx; if ((vp->v_flag & VOBJDIRTY) == 0) { ctx = vp->v_mount->mnt_syncer_ctx; vsetflags(vp, VOBJDIRTY); lwkt_gettoken(&ctx->sc_token); if ((vp->v_flag & VONWORKLST) == 0) vn_syncer_add(vp, syncdelay); lwkt_reltoken(&ctx->sc_token); } }
/* * Add an item to the syncer work queue. * * WARNING: Cannot get vp->v_token here if not already held, we must * depend on the syncer_token (which might already be held by * the caller) to protect v_synclist and VONWORKLST. * * MPSAFE */ void vn_syncer_add(struct vnode *vp, int delay) { struct syncer_ctx *ctx; int slot; ctx = vn_get_syncer(vp); lwkt_gettoken(&ctx->sc_token); if (vp->v_flag & VONWORKLST) LIST_REMOVE(vp, v_synclist); if (delay > syncer_maxdelay - 2) delay = syncer_maxdelay - 2; slot = (ctx->syncer_delayno + delay) & ctx->syncer_mask; LIST_INSERT_HEAD(&ctx->syncer_workitem_pending[slot], vp, v_synclist); vsetflags(vp, VONWORKLST); lwkt_reltoken(&ctx->sc_token); }
/* * Return locked root vnode of a filesystem */ static int smbfs_root(struct mount *mp, struct vnode **vpp) { struct thread *td = curthread; /* XXX */ struct smbmount *smp = VFSTOSMBFS(mp); struct vnode *vp; struct smbnode *np; struct smbfattr fattr; struct ucred *cred; struct smb_cred scred; int error; if (smp == NULL) { SMBERROR("smp == NULL (bug in umount)\n"); return EINVAL; } if (smp->sm_root) { *vpp = SMBTOV(smp->sm_root); return vget(*vpp, LK_EXCLUSIVE | LK_RETRY); } if (td->td_proc) cred = td->td_proc->p_ucred; else cred = proc0.p_ucred; smb_makescred(&scred, td, cred); error = smbfs_smb_lookup(NULL, NULL, 0, &fattr, &scred); if (error) return error; error = smbfs_nget(mp, NULL, "TheRooT", 7, &fattr, &vp); if (error) return error; vsetflags(vp, VROOT); np = VTOSMB(vp); smp->sm_root = np; *vpp = vp; return 0; }
/* * Mount the per-process file descriptors (/dev/fd) */ static int fdesc_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred) { int error = 0; struct fdescmount *fmp; struct vnode *rvp; if (path == NULL) panic("fdesc_mount: cannot mount as root"); /* * Update is a no-op */ if (mp->mnt_flag & MNT_UPDATE) return (EOPNOTSUPP); vfs_add_vnodeops(mp, &fdesc_vnode_vops, &mp->mnt_vn_norm_ops); error = fdesc_allocvp(Froot, FD_ROOT, mp, &rvp); if (error) return (error); fmp = kmalloc(sizeof(struct fdescmount), M_FDESCMNT, M_WAITOK); /* XXX */ rvp->v_type = VDIR; vsetflags(rvp, VROOT); fmp->f_root = rvp; /* XXX -- don't mark as local to work around fts() problems */ /*mp->mnt_flag |= MNT_LOCAL;*/ mp->mnt_data = (qaddr_t) fmp; vfs_getnewfsid(mp); bzero(mp->mnt_stat.f_mntfromname, MNAMELEN); bcopy("fdesc", mp->mnt_stat.f_mntfromname, sizeof("fdesc")); fdesc_statfs(mp, &mp->mnt_stat, cred); return (0); }
/* * Add an item to the syncer work queue. * * WARNING: Cannot get vp->v_token here if not already held, we must * depend on the syncer_token (which might already be held by * the caller) to protect v_synclist and VONWORKLST. * * MPSAFE */ void vn_syncer_add(struct vnode *vp, int delay) { struct syncer_ctx *ctx; int slot; ctx = vp->v_mount->mnt_syncer_ctx; lwkt_gettoken(&ctx->sc_token); if (vp->v_flag & VONWORKLST) LIST_REMOVE(vp, v_synclist); if (delay <= 0) { slot = -delay & ctx->syncer_mask; } else { if (delay > SYNCER_MAXDELAY - 2) delay = SYNCER_MAXDELAY - 2; slot = (ctx->syncer_delayno + delay) & ctx->syncer_mask; } LIST_INSERT_HEAD(&ctx->syncer_workitem_pending[slot], vp, v_synclist); vsetflags(vp, VONWORKLST); lwkt_reltoken(&ctx->sc_token); }
static int ckpt_thaw_proc(struct lwp *lp, struct file *fp) { struct proc *p = lp->lwp_proc; Elf_Phdr *phdr = NULL; Elf_Ehdr *ehdr = NULL; int error; size_t nbyte; TRACE_ENTER; ehdr = kmalloc(sizeof(Elf_Ehdr), M_TEMP, M_ZERO | M_WAITOK); if ((error = elf_gethdr(fp, ehdr)) != 0) goto done; nbyte = sizeof(Elf_Phdr) * ehdr->e_phnum; phdr = kmalloc(nbyte, M_TEMP, M_WAITOK); /* fetch description of program writable mappings */ if ((error = elf_getphdrs(fp, phdr, nbyte)) != 0) goto done; /* fetch notes section containing register state */ if ((error = elf_getnotes(lp, fp, phdr->p_filesz)) != 0) goto done; /* fetch program text vnodes */ if ((error = elf_gettextvp(p, fp)) != 0) goto done; /* fetch signal disposition */ if ((error = elf_getsigs(lp, fp)) != 0) { kprintf("failure in recovering signals\n"); goto done; } /* fetch open files */ if ((error = elf_getfiles(lp, fp)) != 0) goto done; /* handle mappings last in case we are reading from a socket */ error = elf_loadphdrs(fp, phdr, ehdr->e_phnum); /* * Set the textvp to the checkpoint file and mark the vnode so * a future checkpointing of this checkpoint-restored program * will copy out the contents of the mappings rather then trying * to record the vnode info related to the checkpoint file, which * is likely going to be destroyed when the program is re-checkpointed. */ if (error == 0 && fp->f_data && fp->f_type == DTYPE_VNODE) { if (p->p_textvp) vrele(p->p_textvp); p->p_textvp = (struct vnode *)fp->f_data; vsetflags(p->p_textvp, VCKPT); vref(p->p_textvp); } done: if (ehdr) kfree(ehdr, M_TEMP); if (phdr) kfree(phdr, M_TEMP); lwpsignal(p, lp, 35); TRACE_EXIT; return error; }
/* * Get the vnode associated with the given inode, allocating the vnode if * necessary. The vnode will be returned exclusively locked. * * The caller must lock the inode (shared or exclusive). * * Great care must be taken to avoid deadlocks and vnode acquisition/reclaim * races. */ struct vnode * hammer2_igetv(hammer2_inode_t *ip, int *errorp) { hammer2_inode_data_t *ipdata; hammer2_pfsmount_t *pmp; struct vnode *vp; ccms_state_t ostate; pmp = ip->pmp; KKASSERT(pmp != NULL); *errorp = 0; ipdata = &ip->chain->data->ipdata; for (;;) { /* * Attempt to reuse an existing vnode assignment. It is * possible to race a reclaim so the vget() may fail. The * inode must be unlocked during the vget() to avoid a * deadlock against a reclaim. */ vp = ip->vp; if (vp) { /* * Inode must be unlocked during the vget() to avoid * possible deadlocks, but leave the ip ref intact. * * vnode is held to prevent destruction during the * vget(). The vget() can still fail if we lost * a reclaim race on the vnode. */ vhold(vp); ostate = hammer2_inode_lock_temp_release(ip); if (vget(vp, LK_EXCLUSIVE)) { vdrop(vp); hammer2_inode_lock_temp_restore(ip, ostate); continue; } hammer2_inode_lock_temp_restore(ip, ostate); vdrop(vp); /* vp still locked and ref from vget */ if (ip->vp != vp) { kprintf("hammer2: igetv race %p/%p\n", ip->vp, vp); vput(vp); continue; } *errorp = 0; break; } /* * No vnode exists, allocate a new vnode. Beware of * allocation races. This function will return an * exclusively locked and referenced vnode. */ *errorp = getnewvnode(VT_HAMMER2, pmp->mp, &vp, 0, 0); if (*errorp) { kprintf("hammer2: igetv getnewvnode failed %d\n", *errorp); vp = NULL; break; } /* * Lock the inode and check for an allocation race. */ ostate = hammer2_inode_lock_upgrade(ip); if (ip->vp != NULL) { vp->v_type = VBAD; vx_put(vp); hammer2_inode_lock_downgrade(ip, ostate); continue; } switch (ipdata->type) { case HAMMER2_OBJTYPE_DIRECTORY: vp->v_type = VDIR; break; case HAMMER2_OBJTYPE_REGFILE: vp->v_type = VREG; vinitvmio(vp, ipdata->size, HAMMER2_LBUFSIZE, (int)ipdata->size & HAMMER2_LBUFMASK); break; case HAMMER2_OBJTYPE_SOFTLINK: /* * XXX for now we are using the generic file_read * and file_write code so we need a buffer cache * association. */ vp->v_type = VLNK; vinitvmio(vp, ipdata->size, HAMMER2_LBUFSIZE, (int)ipdata->size & HAMMER2_LBUFMASK); break; case HAMMER2_OBJTYPE_CDEV: vp->v_type = VCHR; /* fall through */ case HAMMER2_OBJTYPE_BDEV: vp->v_ops = &pmp->mp->mnt_vn_spec_ops; if (ipdata->type != HAMMER2_OBJTYPE_CDEV) vp->v_type = VBLK; addaliasu(vp, ipdata->rmajor, ipdata->rminor); break; case HAMMER2_OBJTYPE_FIFO: vp->v_type = VFIFO; vp->v_ops = &pmp->mp->mnt_vn_fifo_ops; break; default: panic("hammer2: unhandled objtype %d", ipdata->type); break; } if (ip == pmp->iroot) vsetflags(vp, VROOT); vp->v_data = ip; ip->vp = vp; hammer2_inode_ref(ip); /* vp association */ hammer2_inode_lock_downgrade(ip, ostate); break; } /* * Return non-NULL vp and *errorp == 0, or NULL vp and *errorp != 0. */ if (hammer2_debug & 0x0002) { kprintf("igetv vp %p refs 0x%08x aux 0x%08x\n", vp, vp->v_refcnt, vp->v_auxrefs); } return (vp); }
int ntfs_vgetex(struct mount *mp, ino_t ino, u_int32_t attrtype, char *attrname, u_long lkflags, u_long flags, struct thread *td, struct vnode **vpp) { int error; struct ntfsmount *ntmp; struct ntnode *ip; struct fnode *fp; struct vnode *vp; enum vtype f_type; dprintf(("ntfs_vgetex: ino: %ju, attr: 0x%x:%s, lkf: 0x%lx, f: 0x%lx\n", (uintmax_t) ino, attrtype, attrname?attrname:"", lkflags, flags)); ntmp = VFSTONTFS(mp); *vpp = NULL; /* Get ntnode */ error = ntfs_ntlookup(ntmp, ino, &ip); if (error) { kprintf("ntfs_vget: ntfs_ntget failed\n"); return (error); } /* It may be not initialized fully, so force load it */ if (!(flags & VG_DONTLOADIN) && !(ip->i_flag & IN_LOADED)) { error = ntfs_loadntnode(ntmp, ip); if(error) { kprintf("ntfs_vget: CAN'T LOAD ATTRIBUTES FOR INO: %"PRId64"\n", ip->i_number); ntfs_ntput(ip); return (error); } } error = ntfs_fget(ntmp, ip, attrtype, attrname, &fp); if (error) { kprintf("ntfs_vget: ntfs_fget failed\n"); ntfs_ntput(ip); return (error); } f_type = VINT; if (!(flags & VG_DONTVALIDFN) && !(fp->f_flag & FN_VALID)) { if ((ip->i_frflag & NTFS_FRFLAG_DIR) && (fp->f_attrtype == NTFS_A_DATA && fp->f_attrname == NULL)) { f_type = VDIR; } else if (flags & VG_EXT) { f_type = VINT; fp->f_size = fp->f_allocated = 0; } else { f_type = VREG; error = ntfs_filesize(ntmp, fp, &fp->f_size, &fp->f_allocated); if (error) { ntfs_ntput(ip); return (error); } } fp->f_flag |= FN_VALID; } if (FTOV(fp)) { VGET(FTOV(fp), lkflags); *vpp = FTOV(fp); ntfs_ntput(ip); return (0); } error = getnewvnode(VT_NTFS, ntmp->ntm_mountp, &vp, VLKTIMEOUT, 0); if(error) { ntfs_frele(fp); ntfs_ntput(ip); return (error); } dprintf(("ntfs_vget: vnode: %p for ntnode: %ju\n", vp, (uintmax_t)ino)); fp->f_vp = vp; vp->v_data = fp; vp->v_type = f_type; if (ino == NTFS_ROOTINO) vsetflags(vp, VROOT); /* * Normal files use the buffer cache */ if (f_type == VREG) vinitvmio(vp, fp->f_size, PAGE_SIZE, -1); ntfs_ntput(ip); KKASSERT(lkflags & LK_TYPE_MASK); /* XXX leave vnode locked exclusively from getnewvnode */ *vpp = vp; return (0); }
/* * Common code for mount and mountroot */ int ntfs_mountfs(struct vnode *devvp, struct mount *mp, struct ntfs_args *argsp, struct ucred *cred) { struct buf *bp; struct ntfsmount *ntmp; cdev_t dev; int error, ronly, ncount, i; struct vnode *vp; char cs_local[ICONV_CSNMAXLEN]; char cs_ntfs[ICONV_CSNMAXLEN]; /* * Disallow multiple mounts of the same device. * Disallow mounting of a device that is currently in use * (except for root, which might share swap device for miniroot). * Flush out any old buffers remaining from a previous use. */ error = vfs_mountedon(devvp); if (error) return (error); ncount = vcount(devvp); if (devvp->v_object) ncount -= 1; if (ncount > 1) return (EBUSY); VN_LOCK(devvp, LK_EXCLUSIVE | LK_RETRY); error = vinvalbuf(devvp, V_SAVE, 0, 0); VOP__UNLOCK(devvp, 0); if (error) return (error); ronly = (mp->mnt_flag & MNT_RDONLY) != 0; VN_LOCK(devvp, LK_EXCLUSIVE | LK_RETRY); error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, NULL); VOP__UNLOCK(devvp, 0); if (error) return (error); dev = devvp->v_rdev; bp = NULL; error = bread(devvp, BBLOCK, BBSIZE, &bp); if (error) goto out; ntmp = kmalloc(sizeof *ntmp, M_NTFSMNT, M_WAITOK | M_ZERO); bcopy( bp->b_data, &ntmp->ntm_bootfile, sizeof(struct bootfile) ); /* * We must not cache the boot block if its size is not exactly * one cluster in order to avoid confusing the buffer cache when * the boot file is read later by ntfs_readntvattr_plain(), which * reads a cluster at a time. */ if (ntfs_cntob(1) != BBSIZE) bp->b_flags |= B_NOCACHE; brelse( bp ); bp = NULL; if (strncmp(ntmp->ntm_bootfile.bf_sysid, NTFS_BBID, NTFS_BBIDLEN)) { error = EINVAL; dprintf(("ntfs_mountfs: invalid boot block\n")); goto out; } { int8_t cpr = ntmp->ntm_mftrecsz; if( cpr > 0 ) ntmp->ntm_bpmftrec = ntmp->ntm_spc * cpr; else ntmp->ntm_bpmftrec = (1 << (-cpr)) / ntmp->ntm_bps; } dprintf(("ntfs_mountfs(): bps: %d, spc: %d, media: %x, mftrecsz: %d (%d sects)\n", ntmp->ntm_bps,ntmp->ntm_spc,ntmp->ntm_bootfile.bf_media, ntmp->ntm_mftrecsz,ntmp->ntm_bpmftrec)); dprintf(("ntfs_mountfs(): mftcn: 0x%x|0x%x\n", (u_int32_t)ntmp->ntm_mftcn,(u_int32_t)ntmp->ntm_mftmirrcn)); ntmp->ntm_mountp = mp; ntmp->ntm_dev = dev; ntmp->ntm_devvp = devvp; ntmp->ntm_uid = argsp->uid; ntmp->ntm_gid = argsp->gid; ntmp->ntm_mode = argsp->mode; ntmp->ntm_flag = argsp->flag; if (argsp->flag & NTFS_MFLAG_KICONV && ntfs_iconv) { bcopy(argsp->cs_local, cs_local, sizeof(cs_local)); bcopy(argsp->cs_ntfs, cs_ntfs, sizeof(cs_ntfs)); ntfs_82u_init(ntmp, cs_local, cs_ntfs); ntfs_u28_init(ntmp, NULL, cs_local, cs_ntfs); } else { ntfs_82u_init(ntmp, NULL, NULL); ntfs_u28_init(ntmp, ntmp->ntm_82u, NULL, NULL); } mp->mnt_data = (qaddr_t)ntmp; dprintf(("ntfs_mountfs(): case-%s,%s uid: %d, gid: %d, mode: %o\n", (ntmp->ntm_flag & NTFS_MFLAG_CASEINS)?"insens.":"sens.", (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES)?" allnames,":"", ntmp->ntm_uid, ntmp->ntm_gid, ntmp->ntm_mode)); vfs_add_vnodeops(mp, &ntfs_vnode_vops, &mp->mnt_vn_norm_ops); /* * We read in some system nodes to do not allow * reclaim them and to have everytime access to them. */ { int pi[3] = { NTFS_MFTINO, NTFS_ROOTINO, NTFS_BITMAPINO }; for (i=0; i<3; i++) { error = VFS_VGET(mp, NULL, pi[i], &(ntmp->ntm_sysvn[pi[i]])); if(error) goto out1; vsetflags(ntmp->ntm_sysvn[pi[i]], VSYSTEM); vref(ntmp->ntm_sysvn[pi[i]]); vput(ntmp->ntm_sysvn[pi[i]]); } } /* read the Unicode lowercase --> uppercase translation table, * if necessary */ if ((error = ntfs_toupper_use(mp, ntmp))) goto out1; /* * Scan $BitMap and count free clusters */ error = ntfs_calccfree(ntmp, &ntmp->ntm_cfree); if(error) goto out1; /* * Read and translate to internal format attribute * definition file. */ { int num,j; struct attrdef ad; /* Open $AttrDef */ error = VFS_VGET(mp, NULL, NTFS_ATTRDEFINO, &vp); if(error) goto out1; /* Count valid entries */ for(num=0;;num++) { error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL, num * sizeof(ad), sizeof(ad), &ad, NULL); if (error) goto out1; if (ad.ad_name[0] == 0) break; } /* Alloc memory for attribute definitions */ ntmp->ntm_ad = kmalloc(num * sizeof(struct ntvattrdef), M_NTFSMNT, M_WAITOK); ntmp->ntm_adnum = num; /* Read them and translate */ for(i=0;i<num;i++){ error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL, i * sizeof(ad), sizeof(ad), &ad, NULL); if (error) goto out1; j = 0; do { ntmp->ntm_ad[i].ad_name[j] = ad.ad_name[j]; } while(ad.ad_name[j++]); ntmp->ntm_ad[i].ad_namelen = j - 1; ntmp->ntm_ad[i].ad_type = ad.ad_type; } vput(vp); } mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; mp->mnt_maxsymlinklen = 0; mp->mnt_flag |= MNT_LOCAL; dev->si_mountpoint = mp; return (0); out1: for(i=0;i<NTFS_SYSNODESNUM;i++) if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]); if (vflush(mp, 0, 0)) dprintf(("ntfs_mountfs: vflush failed\n")); out: dev->si_mountpoint = NULL; if (bp) brelse(bp); vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NULL); vn_unlock(devvp); return (error); }
static int devfs_spec_open(struct vop_open_args *ap) { struct vnode *vp = ap->a_vp; struct vnode *orig_vp = NULL; struct devfs_node *node = DEVFS_NODE(vp); struct devfs_node *newnode; cdev_t dev, ndev = NULL; int error = 0; if (node) { if (node->d_dev == NULL) return ENXIO; if (!devfs_node_is_accessible(node)) return ENOENT; } if ((dev = vp->v_rdev) == NULL) return ENXIO; vn_lock(vp, LK_UPGRADE | LK_RETRY); if (node && ap->a_fp) { devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_spec_open: -1.1-\n"); lockmgr(&devfs_lock, LK_EXCLUSIVE); ndev = devfs_clone(dev, node->d_dir.d_name, node->d_dir.d_namlen, ap->a_mode, ap->a_cred); if (ndev != NULL) { newnode = devfs_create_device_node( DEVFS_MNTDATA(vp->v_mount)->root_node, ndev, NULL, NULL); /* XXX: possibly destroy device if this happens */ if (newnode != NULL) { dev = ndev; devfs_link_dev(dev); devfs_debug(DEVFS_DEBUG_DEBUG, "parent here is: %s, node is: |%s|\n", ((node->parent->node_type == Nroot) ? "ROOT!" : node->parent->d_dir.d_name), newnode->d_dir.d_name); devfs_debug(DEVFS_DEBUG_DEBUG, "test: %s\n", ((struct devfs_node *)(TAILQ_LAST(DEVFS_DENODE_HEAD(node->parent), devfs_node_head)))->d_dir.d_name); /* * orig_vp is set to the original vp if we cloned. */ /* node->flags |= DEVFS_CLONED; */ devfs_allocv(&vp, newnode); orig_vp = ap->a_vp; ap->a_vp = vp; } } lockmgr(&devfs_lock, LK_RELEASE); } devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_spec_open() called on %s! \n", dev->si_name); /* * Make this field valid before any I/O in ->d_open */ if (!dev->si_iosize_max) /* XXX: old DFLTPHYS == 64KB dependency */ dev->si_iosize_max = min(MAXPHYS,64*1024); if (dev_dflags(dev) & D_TTY) vsetflags(vp, VISTTY); /* * Open underlying device */ vn_unlock(vp); error = dev_dopen(dev, ap->a_mode, S_IFCHR, ap->a_cred, ap->a_fp); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); /* * Clean up any cloned vp if we error out. */ if (error) { if (orig_vp) { vput(vp); ap->a_vp = orig_vp; /* orig_vp = NULL; */ } return error; } /* * This checks if the disk device is going to be opened for writing. * It will be only allowed in the cases where securelevel permits it * and it's not mounted R/W. */ if ((dev_dflags(dev) & D_DISK) && (ap->a_mode & FWRITE) && (ap->a_cred != FSCRED)) { /* Very secure mode. No open for writing allowed */ if (securelevel >= 2) return EPERM; /* * If it is mounted R/W, do not allow to open for writing. * In the case it's mounted read-only but securelevel * is >= 1, then do not allow opening for writing either. */ if (vfs_mountedon(vp)) { if (!(dev->si_mountpoint->mnt_flag & MNT_RDONLY)) return EBUSY; else if (securelevel >= 1) return EPERM; } } if (dev_dflags(dev) & D_TTY) { if (dev->si_tty) { struct tty *tp; tp = dev->si_tty; if (!tp->t_stop) { devfs_debug(DEVFS_DEBUG_DEBUG, "devfs: no t_stop\n"); tp->t_stop = nottystop; } } } if (vn_isdisk(vp, NULL)) { if (!dev->si_bsize_phys) dev->si_bsize_phys = DEV_BSIZE; vinitvmio(vp, IDX_TO_OFF(INT_MAX), PAGE_SIZE, -1); } vop_stdopen(ap); #if 0 if (node) nanotime(&node->atime); #endif /* * If we replaced the vp the vop_stdopen() call will have loaded * it into fp->f_data and vref()d the vp, giving us two refs. So * instead of just unlocking it here we have to vput() it. */ if (orig_vp) vput(vp); /* Ugly pty magic, to make pty devices appear once they are opened */ if (node && (node->flags & DEVFS_PTY) == DEVFS_PTY) node->flags &= ~DEVFS_INVISIBLE; if (ap->a_fp) { KKASSERT(ap->a_fp->f_type == DTYPE_VNODE); KKASSERT((ap->a_fp->f_flag & FMASK) == (ap->a_mode & FMASK)); ap->a_fp->f_ops = &devfs_dev_fileops; KKASSERT(ap->a_fp->f_data == (void *)vp); } return 0; }
int ufs_quotaon(struct ucred *cred, struct mount *mp, int type, caddr_t fname) { struct ufsmount *ump = VFSTOUFS(mp); struct vnode *vp, **vpp; struct ufs_dquot *dq; int error; struct nlookupdata nd; struct scaninfo scaninfo; vpp = &ump->um_quotas[type]; error = nlookup_init(&nd, fname, UIO_USERSPACE, NLC_FOLLOW|NLC_LOCKVP); if (error == 0) error = vn_open(&nd, NULL, FREAD|FWRITE, 0); if (error == 0 && nd.nl_open_vp->v_type != VREG) error = EACCES; if (error) { nlookup_done(&nd); return (error); } vp = nd.nl_open_vp; nd.nl_open_vp = NULL; nlookup_done(&nd); vn_unlock(vp); if (*vpp != vp) ufs_quotaoff(mp, type); ump->um_qflags[type] |= QTF_OPENING; mp->mnt_flag |= MNT_QUOTA; vsetflags(vp, VSYSTEM); *vpp = vp; /* XXX release duplicate vp if *vpp == vp? */ /* * Save the credential of the process that turned on quotas. * Set up the time limits for this quota. */ ump->um_cred[type] = crhold(cred); ump->um_btime[type] = MAX_DQ_TIME; ump->um_itime[type] = MAX_IQ_TIME; if (ufs_dqget(NULLVP, 0, ump, type, &dq) == 0) { if (dq->dq_btime > 0) ump->um_btime[type] = dq->dq_btime; if (dq->dq_itime > 0) ump->um_itime[type] = dq->dq_itime; ufs_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. */ scaninfo.rescan = 1; while (scaninfo.rescan) { scaninfo.rescan = 0; error = vmntvnodescan(mp, VMSC_GETVP, NULL, ufs_quotaon_scan, &scaninfo); if (error) break; } ump->um_qflags[type] &= ~QTF_OPENING; if (error) ufs_quotaoff(mp, type); return (error); }
/* Return locked vnode to root of a filesystem */ static int nwfs_root(struct mount *mp, struct vnode **vpp) { struct vnode *vp; struct nwmount *nmp; struct nwnode *np; struct ncp_conn *conn; struct nw_entry_info fattr; struct thread *td = curthread; /* XXX */ struct ucred *cred; int error, nsf, opt; u_char vol; KKASSERT(td->td_proc); cred = td->td_proc->p_ucred; nmp = VFSTONWFS(mp); conn = NWFSTOCONN(nmp); if (nmp->n_root) { *vpp = NWTOV(nmp->n_root); while (vget(*vpp, LK_EXCLUSIVE) != 0) /* XXX */ ; return 0; } error = ncp_lookup_volume(conn, nmp->m.mounted_vol, &vol, &nmp->n_rootent.f_id, td, cred); if (error) return ENOENT; nmp->n_volume = vol; error = ncp_get_namespaces(conn, vol, &nsf, td, cred); if (error) return ENOENT; if (nsf & NW_NSB_OS2) { NCPVODEBUG("volume %s has os2 namespace\n",nmp->m.mounted_vol); if ((nmp->m.flags & NWFS_MOUNT_NO_OS2) == 0) { nmp->name_space = NW_NS_OS2; nmp->m.nls.opt &= ~NWHP_DOS; } } opt = nmp->m.nls.opt; nsf = opt & (NWHP_UPPER | NWHP_LOWER); if (opt & NWHP_DOS) { if (nsf == (NWHP_UPPER | NWHP_LOWER)) { nmp->m.nls.opt &= ~(NWHP_LOWER | NWHP_UPPER); } else if (nsf == 0) { nmp->m.nls.opt |= NWHP_LOWER; } } else { if (nsf == (NWHP_UPPER | NWHP_LOWER)) { nmp->m.nls.opt &= ~(NWHP_LOWER | NWHP_UPPER); } } if (nmp->m.root_path[0]) { nmp->m.root_path[0]--; error = ncp_obtain_info(nmp, nmp->n_rootent.f_id, -nmp->m.root_path[0], nmp->m.root_path, &fattr, td, cred); if (error) { NCPFATAL("Invalid root path specified\n"); return ENOENT; } nmp->n_rootent.f_parent = fattr.dirEntNum; nmp->m.root_path[0]++; error = ncp_obtain_info(nmp, nmp->n_rootent.f_id, -nmp->m.root_path[0], nmp->m.root_path, &fattr, td, cred); if (error) { NCPFATAL("Invalid root path specified\n"); return ENOENT; } nmp->n_rootent.f_id = fattr.dirEntNum; } else { error = ncp_obtain_info(nmp, nmp->n_rootent.f_id, 0, NULL, &fattr, td, cred); if (error) { NCPFATAL("Can't obtain volume info\n"); return ENOENT; } fattr.nameLen = strlen(strcpy(fattr.entryName, NWFS_ROOTVOL)); nmp->n_rootent.f_parent = nmp->n_rootent.f_id; } error = nwfs_nget(mp, nmp->n_rootent, &fattr, NULL, &vp); if (error) return (error); vsetflags(vp, VROOT); np = VTONW(vp); if (nmp->m.root_path[0] == 0) np->n_flag |= NVOLUME; nmp->n_root = np; /* error = VOP_GETATTR(vp, &vattr); if (error) { vput(vp); NCPFATAL("Can't get root directory entry\n"); return error; }*/ *vpp = vp; return (0); }
/* * Allocates a new vnode for the node node or returns a new reference to * an existing one if the node had already a vnode referencing it. The * resulting locked vnode is returned in *vpp. * * Returns zero on success or an appropriate error code on failure. * * The caller must ensure that node cannot go away (usually by holding * the related directory entry). * * If dnode is non-NULL this routine avoids deadlocking against it but * can return EAGAIN. Caller must try again. The dnode lock will cycle * in this case, it remains locked on return in all cases. dnode must * be shared-locked. */ int tmpfs_alloc_vp(struct mount *mp, struct tmpfs_node *dnode, struct tmpfs_node *node, int lkflag, struct vnode **vpp) { int error = 0; struct vnode *vp; loop: /* * Interlocked extraction from node. This can race many things. * We have to get a soft reference on the vnode while we hold * the node locked, then acquire it properly and check for races. */ TMPFS_NODE_LOCK(node); if ((vp = node->tn_vnode) != NULL) { KKASSERT((node->tn_vpstate & TMPFS_VNODE_DOOMED) == 0); vhold(vp); TMPFS_NODE_UNLOCK(node); if (dnode) { /* * Special-case handling to avoid deadlocking against * dnode. This case has been validated and occurs * every so often during synth builds. */ if (vget(vp, (lkflag & ~LK_RETRY) | LK_NOWAIT | LK_EXCLUSIVE) != 0) { TMPFS_NODE_UNLOCK(dnode); if (vget(vp, (lkflag & ~LK_RETRY) | LK_SLEEPFAIL | LK_EXCLUSIVE) == 0) { vn_unlock(vp); } vdrop(vp); TMPFS_NODE_LOCK_SH(dnode); return EAGAIN; } } else { /* * Normal path */ if (vget(vp, lkflag | LK_EXCLUSIVE) != 0) { vdrop(vp); goto loop; } } if (node->tn_vnode != vp) { vput(vp); vdrop(vp); goto loop; } vdrop(vp); goto out; } /* vp is NULL */ /* * This should never happen. */ if (node->tn_vpstate & TMPFS_VNODE_DOOMED) { TMPFS_NODE_UNLOCK(node); error = ENOENT; goto out; } /* * Interlock against other calls to tmpfs_alloc_vp() trying to * allocate and assign a vp to node. */ if (node->tn_vpstate & TMPFS_VNODE_ALLOCATING) { node->tn_vpstate |= TMPFS_VNODE_WANT; error = tsleep(&node->tn_vpstate, PINTERLOCKED | PCATCH, "tmpfs_alloc_vp", 0); TMPFS_NODE_UNLOCK(node); if (error) return error; goto loop; } node->tn_vpstate |= TMPFS_VNODE_ALLOCATING; TMPFS_NODE_UNLOCK(node); /* * Allocate a new vnode (may block). The ALLOCATING flag should * prevent a race against someone else assigning node->tn_vnode. */ error = getnewvnode(VT_TMPFS, mp, &vp, VLKTIMEOUT, LK_CANRECURSE); if (error != 0) goto unlock; KKASSERT(node->tn_vnode == NULL); KKASSERT(vp != NULL); vp->v_data = node; vp->v_type = node->tn_type; /* Type-specific initialization. */ switch (node->tn_type) { case VBLK: /* FALLTHROUGH */ case VCHR: /* FALLTHROUGH */ case VSOCK: break; case VREG: /* * VMIO is mandatory. Tmpfs also supports KVABIO * for its tmpfs_strategy(). */ vsetflags(vp, VKVABIO); vinitvmio(vp, node->tn_size, TMPFS_BLKSIZE, -1); break; case VLNK: break; case VFIFO: vp->v_ops = &mp->mnt_vn_fifo_ops; break; case VDIR: break; default: panic("tmpfs_alloc_vp: type %p %d", node, (int)node->tn_type); } unlock: TMPFS_NODE_LOCK(node); KKASSERT(node->tn_vpstate & TMPFS_VNODE_ALLOCATING); node->tn_vpstate &= ~TMPFS_VNODE_ALLOCATING; node->tn_vnode = vp; if (node->tn_vpstate & TMPFS_VNODE_WANT) { node->tn_vpstate &= ~TMPFS_VNODE_WANT; TMPFS_NODE_UNLOCK(node); wakeup(&node->tn_vpstate); } else { TMPFS_NODE_UNLOCK(node); } out: *vpp = vp; KKASSERT(IFF(error == 0, *vpp != NULL && vn_islocked(*vpp))); return error; }
/* * Common code for vnode open operations. Check permissions, and call * the VOP_NOPEN or VOP_NCREATE routine. * * The caller is responsible for setting up nd with nlookup_init() and * for cleaning it up with nlookup_done(), whether we return an error * or not. * * On success nd->nl_open_vp will hold a referenced and, if requested, * locked vnode. A locked vnode is requested via NLC_LOCKVP. If fp * is non-NULL the vnode will be installed in the file pointer. * * NOTE: The vnode is referenced just once on return whether or not it * is also installed in the file pointer. */ int vn_open(struct nlookupdata *nd, struct file *fp, int fmode, int cmode) { struct vnode *vp; struct ucred *cred = nd->nl_cred; struct vattr vat; struct vattr *vap = &vat; int error; u_int flags; uint64_t osize; struct mount *mp; /* * Certain combinations are illegal */ if ((fmode & (FWRITE | O_TRUNC)) == O_TRUNC) return(EACCES); /* * Lookup the path and create or obtain the vnode. After a * successful lookup a locked nd->nl_nch will be returned. * * The result of this section should be a locked vnode. * * XXX with only a little work we should be able to avoid locking * the vnode if FWRITE, O_CREAT, and O_TRUNC are *not* set. */ nd->nl_flags |= NLC_OPEN; if (fmode & O_APPEND) nd->nl_flags |= NLC_APPEND; if (fmode & O_TRUNC) nd->nl_flags |= NLC_TRUNCATE; if (fmode & FREAD) nd->nl_flags |= NLC_READ; if (fmode & FWRITE) nd->nl_flags |= NLC_WRITE; if ((fmode & O_EXCL) == 0 && (fmode & O_NOFOLLOW) == 0) nd->nl_flags |= NLC_FOLLOW; if (fmode & O_CREAT) { /* * CONDITIONAL CREATE FILE CASE * * Setting NLC_CREATE causes a negative hit to store * the negative hit ncp and not return an error. Then * nc_error or nc_vp may be checked to see if the ncp * represents a negative hit. NLC_CREATE also requires * write permission on the governing directory or EPERM * is returned. */ nd->nl_flags |= NLC_CREATE; nd->nl_flags |= NLC_REFDVP; bwillinode(1); error = nlookup(nd); } else { /* * NORMAL OPEN FILE CASE */ error = nlookup(nd); } if (error) return (error); /* * split case to allow us to re-resolve and retry the ncp in case * we get ESTALE. */ again: if (fmode & O_CREAT) { if (nd->nl_nch.ncp->nc_vp == NULL) { if ((error = ncp_writechk(&nd->nl_nch)) != 0) return (error); VATTR_NULL(vap); vap->va_type = VREG; vap->va_mode = cmode; if (fmode & O_EXCL) vap->va_vaflags |= VA_EXCLUSIVE; error = VOP_NCREATE(&nd->nl_nch, nd->nl_dvp, &vp, nd->nl_cred, vap); if (error) return (error); fmode &= ~O_TRUNC; /* locked vnode is returned */ } else { if (fmode & O_EXCL) { error = EEXIST; } else { error = cache_vget(&nd->nl_nch, cred, LK_EXCLUSIVE, &vp); } if (error) return (error); fmode &= ~O_CREAT; } } else { error = cache_vget(&nd->nl_nch, cred, LK_EXCLUSIVE, &vp); if (error) return (error); } /* * We have a locked vnode and ncp now. Note that the ncp will * be cleaned up by the caller if nd->nl_nch is left intact. */ if (vp->v_type == VLNK) { error = EMLINK; goto bad; } if (vp->v_type == VSOCK) { error = EOPNOTSUPP; goto bad; } if ((fmode & O_CREAT) == 0) { if (fmode & (FWRITE | O_TRUNC)) { if (vp->v_type == VDIR) { error = EISDIR; goto bad; } error = vn_writechk(vp, &nd->nl_nch); if (error) { /* * Special stale handling, re-resolve the * vnode. */ if (error == ESTALE) { vput(vp); vp = NULL; cache_setunresolved(&nd->nl_nch); error = cache_resolve(&nd->nl_nch, cred); if (error == 0) goto again; } goto bad; } } } if (fmode & O_TRUNC) { vn_unlock(vp); /* XXX */ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); /* XXX */ osize = vp->v_filesize; VATTR_NULL(vap); vap->va_size = 0; error = VOP_SETATTR(vp, vap, cred); if (error) goto bad; error = VOP_GETATTR(vp, vap); if (error) goto bad; mp = vq_vptomp(vp); VFS_ACCOUNT(mp, vap->va_uid, vap->va_gid, -osize); } /* * Set or clear VNSWAPCACHE on the vp based on nd->nl_nch.ncp->nc_flag. * These particular bits a tracked all the way from the root. * * NOTE: Might not work properly on NFS servers due to the * disconnected namecache. */ flags = nd->nl_nch.ncp->nc_flag; if ((flags & (NCF_UF_CACHE | NCF_UF_PCACHE)) && (flags & (NCF_SF_NOCACHE | NCF_SF_PNOCACHE)) == 0) { vsetflags(vp, VSWAPCACHE); } else { vclrflags(vp, VSWAPCACHE); } /* * Setup the fp so VOP_OPEN can override it. No descriptor has been * associated with the fp yet so we own it clean. * * f_nchandle inherits nl_nch. This used to be necessary only for * directories but now we do it unconditionally so f*() ops * such as fchmod() can access the actual namespace that was * used to open the file. */ if (fp) { if (nd->nl_flags & NLC_APPENDONLY) fmode |= FAPPENDONLY; fp->f_nchandle = nd->nl_nch; cache_zero(&nd->nl_nch); cache_unlock(&fp->f_nchandle); } /* * Get rid of nl_nch. vn_open does not return it (it returns the * vnode or the file pointer). Note: we can't leave nl_nch locked * through the VOP_OPEN anyway since the VOP_OPEN may block, e.g. * on /dev/ttyd0 */ if (nd->nl_nch.ncp) cache_put(&nd->nl_nch); error = VOP_OPEN(vp, fmode, cred, fp); if (error) { /* * setting f_ops to &badfileops will prevent the descriptor * code from trying to close and release the vnode, since * the open failed we do not want to call close. */ if (fp) { fp->f_data = NULL; fp->f_ops = &badfileops; } goto bad; } #if 0 /* * Assert that VREG files have been setup for vmio. */ KASSERT(vp->v_type != VREG || vp->v_object != NULL, ("vn_open: regular file was not VMIO enabled!")); #endif /* * Return the vnode. XXX needs some cleaning up. The vnode is * only returned in the fp == NULL case. */ if (fp == NULL) { nd->nl_open_vp = vp; nd->nl_vp_fmode = fmode; if ((nd->nl_flags & NLC_LOCKVP) == 0) vn_unlock(vp); } else { vput(vp); } return (0); bad: if (vp) vput(vp); return (error); }
int vfs_mountroot_devfs(void) { struct vnode *vp; struct nchandle nch; struct nlookupdata nd; struct mount *mp; struct vfsconf *vfsp; int error; struct ucred *cred = proc0.p_ucred; const char *devfs_path, *init_chroot; char *dev_malloced = NULL; if ((init_chroot = kgetenv("init_chroot")) != NULL) { size_t l; l = strlen(init_chroot) + sizeof("/dev"); dev_malloced = kmalloc(l, M_MOUNT, M_WAITOK); ksnprintf(dev_malloced, l, "%s/dev", init_chroot); devfs_path = dev_malloced; } else { devfs_path = "/dev"; } /* * Lookup the requested path and extract the nch and vnode. */ error = nlookup_init_raw(&nd, devfs_path, UIO_SYSSPACE, NLC_FOLLOW, cred, &rootnch); if (error == 0) { devfs_debug(DEVFS_DEBUG_DEBUG, "vfs_mountroot_devfs: nlookup_init is ok...\n"); if ((error = nlookup(&nd)) == 0) { devfs_debug(DEVFS_DEBUG_DEBUG, "vfs_mountroot_devfs: nlookup is ok...\n"); if (nd.nl_nch.ncp->nc_vp == NULL) { devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: nlookup: simply not found\n"); error = ENOENT; } } } if (dev_malloced != NULL) kfree(dev_malloced, M_MOUNT), dev_malloced = NULL; devfs_path = NULL; if (error) { nlookup_done(&nd); devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: nlookup failed, error: %d\n", error); return (error); } /* * Extract the locked+refd ncp and cleanup the nd structure */ nch = nd.nl_nch; cache_zero(&nd.nl_nch); nlookup_done(&nd); /* * now we have the locked ref'd nch and unreferenced vnode. */ vp = nch.ncp->nc_vp; if ((error = vget(vp, LK_EXCLUSIVE)) != 0) { cache_put(&nch); devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: vget failed\n"); return (error); } cache_unlock(&nch); if ((error = vinvalbuf(vp, V_SAVE, 0, 0)) != 0) { cache_drop(&nch); vput(vp); devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: vinvalbuf failed\n"); return (error); } if (vp->v_type != VDIR) { cache_drop(&nch); vput(vp); devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: vp is not VDIR\n"); return (ENOTDIR); } vfsp = vfsconf_find_by_name("devfs"); vsetflags(vp, VMOUNT); /* * Allocate and initialize the filesystem. */ mp = kmalloc(sizeof(struct mount), M_MOUNT, M_ZERO|M_WAITOK); mount_init(mp); vfs_busy(mp, LK_NOWAIT); mp->mnt_op = vfsp->vfc_vfsops; mp->mnt_vfc = vfsp; vfsp->vfc_refcount++; mp->mnt_stat.f_type = vfsp->vfc_typenum; mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK; strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN); mp->mnt_stat.f_owner = cred->cr_uid; vn_unlock(vp); /* * Mount the filesystem. */ error = VFS_MOUNT(mp, "/dev", NULL, cred); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); /* * Put the new filesystem on the mount list after root. The mount * point gets its own mnt_ncmountpt (unless the VFS already set one * up) which represents the root of the mount. The lookup code * detects the mount point going forward and checks the root of * the mount going backwards. * * It is not necessary to invalidate or purge the vnode underneath * because elements under the mount will be given their own glue * namecache record. */ if (!error) { if (mp->mnt_ncmountpt.ncp == NULL) { /* * allocate, then unlock, but leave the ref intact */ cache_allocroot(&mp->mnt_ncmountpt, mp, NULL); cache_unlock(&mp->mnt_ncmountpt); } mp->mnt_ncmounton = nch; /* inherits ref */ nch.ncp->nc_flag |= NCF_ISMOUNTPT; /* XXX get the root of the fs and cache_setvp(mnt_ncmountpt...) */ vclrflags(vp, VMOUNT); mountlist_insert(mp, MNTINS_LAST); vn_unlock(vp); //checkdirs(&mp->mnt_ncmounton, &mp->mnt_ncmountpt); error = vfs_allocate_syncvnode(mp); if (error) { devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: vfs_allocate_syncvnode failed\n"); } vfs_unbusy(mp); error = VFS_START(mp, 0); vrele(vp); } else { vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_coherency_ops); vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_journal_ops); vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_norm_ops); vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_spec_ops); vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_fifo_ops); vclrflags(vp, VMOUNT); mp->mnt_vfc->vfc_refcount--; vfs_unbusy(mp); kfree(mp, M_MOUNT); cache_drop(&nch); vput(vp); devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: mount failed\n"); } devfs_debug(DEVFS_DEBUG_DEBUG, "rootmount_devfs done with error: %d\n", error); return (error); }
/* * Allocate a VM object for a vnode, typically a regular file vnode. * * Some additional information is required to generate a properly sized * object which covers the entire buffer cache buffer straddling the file * EOF. Userland does not see the extra pages as the VM fault code tests * against v_filesize. */ vm_object_t vnode_pager_alloc(void *handle, off_t length, vm_prot_t prot, off_t offset, int blksize, int boff) { vm_object_t object; struct vnode *vp; off_t loffset; vm_pindex_t lsize; /* * Pageout to vnode, no can do yet. */ if (handle == NULL) return (NULL); /* * XXX hack - This initialization should be put somewhere else. */ if (vnode_pbuf_freecnt < 0) { vnode_pbuf_freecnt = nswbuf / 2 + 1; } /* * Serialize potential vnode/object teardowns and interlocks */ vp = (struct vnode *)handle; lwkt_gettoken(&vp->v_token); /* * Prevent race condition when allocating the object. This * can happen with NFS vnodes since the nfsnode isn't locked. */ while (vp->v_flag & VOLOCK) { vsetflags(vp, VOWANT); tsleep(vp, 0, "vnpobj", 0); } vsetflags(vp, VOLOCK); lwkt_reltoken(&vp->v_token); /* * If the object is being terminated, wait for it to * go away. */ while ((object = vp->v_object) != NULL) { vm_object_hold(object); if ((object->flags & OBJ_DEAD) == 0) break; vm_object_dead_sleep(object, "vadead"); vm_object_drop(object); } if (vp->v_sysref.refcnt <= 0) panic("vnode_pager_alloc: no vnode reference"); /* * Round up to the *next* block, then destroy the buffers in question. * Since we are only removing some of the buffers we must rely on the * scan count to determine whether a loop is necessary. * * Destroy any pages beyond the last buffer. */ if (boff < 0) boff = (int)(length % blksize); if (boff) loffset = length + (blksize - boff); else loffset = length; lsize = OFF_TO_IDX(round_page64(loffset)); if (object == NULL) { /* * And an object of the appropriate size */ object = vm_object_allocate_hold(OBJT_VNODE, lsize); object->handle = handle; vp->v_object = object; vp->v_filesize = length; if (vp->v_mount && (vp->v_mount->mnt_kern_flag & MNTK_NOMSYNC)) vm_object_set_flag(object, OBJ_NOMSYNC); } else { object->ref_count++; if (object->size != lsize) { kprintf("vnode_pager_alloc: Warning, objsize " "mismatch %jd/%jd vp=%p obj=%p\n", (intmax_t)object->size, (intmax_t)lsize, vp, object); } if (vp->v_filesize != length) { kprintf("vnode_pager_alloc: Warning, filesize " "mismatch %jd/%jd vp=%p obj=%p\n", (intmax_t)vp->v_filesize, (intmax_t)length, vp, object); } } vref(vp); lwkt_gettoken(&vp->v_token); vclrflags(vp, VOLOCK); if (vp->v_flag & VOWANT) { vclrflags(vp, VOWANT); wakeup(vp); } lwkt_reltoken(&vp->v_token); vm_object_drop(object); return (object); }