uvm_swap.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,884 行 · 第 1/4 页
C
1,884 行
for (sdp = CIRCLEQ_FIRST(&spp->spi_swapdev); sdp != (void *)&spp->spi_swapdev; sdp = CIRCLEQ_NEXT(sdp, swd_next)) if (pgno >= sdp->swd_drumoffset && pgno < (sdp->swd_drumoffset + sdp->swd_drumsize)) { return sdp; } return NULL;}/* * sys_swapctl: main entry point for swapctl(2) system call * [with two helper functions: swap_on and swap_off] */intsys_swapctl(p, v, retval) struct proc *p; void *v; register_t *retval;{ struct sys_swapctl_args /* { syscallarg(int) cmd; syscallarg(void *) arg; syscallarg(int) misc; } */ *uap = (struct sys_swapctl_args *)v; struct vnode *vp;#ifndef OSKIT struct nameidata nd;#endif struct swappri *spp; struct swapdev *sdp; struct swapent *sep;#ifndef OSKIT char userpath[PATH_MAX + 1]; size_t len;#endif int count, error, misc; int priority; UVMHIST_FUNC("sys_swapctl"); UVMHIST_CALLED(pdhist); misc = SCARG(uap, misc); /* * ensure serialized syscall access by grabbing the swap_syscall_lock */ lockmgr(&swap_syscall_lock, LK_EXCLUSIVE, NULL); /* * we handle the non-priv NSWAP and STATS request first. * * SWAP_NSWAP: return number of config'd swap devices * [can also be obtained with uvmexp sysctl] */ if (SCARG(uap, cmd) == SWAP_NSWAP) { UVMHIST_LOG(pdhist, "<- done SWAP_NSWAP=%d", uvmexp.nswapdev, 0, 0, 0); *retval = uvmexp.nswapdev; error = 0; goto out; } /* * SWAP_STATS: get stats on current # of configured swap devs * * note that the swap_priority list can't change as long * as we are holding the swap_syscall_lock. we don't want * to grab the uvm.swap_data_lock because we may fault&sleep during * copyout() and we don't want to be holding that lock then! */ if (SCARG(uap, cmd) == SWAP_STATS#if defined(COMPAT_13) || SCARG(uap, cmd) == SWAP_OSTATS#endif ) { sep = (struct swapent *)SCARG(uap, arg); count = 0; for (spp = LIST_FIRST(&swap_priority); spp != NULL; spp = LIST_NEXT(spp, spi_swappri)) { for (sdp = CIRCLEQ_FIRST(&spp->spi_swapdev); sdp != (void *)&spp->spi_swapdev && misc-- > 0; sdp = CIRCLEQ_NEXT(sdp, swd_next)) { /* * backwards compatibility for system call. * note that we use 'struct oswapent' as an * overlay into both 'struct swapdev' and * the userland 'struct swapent', as we * want to retain backwards compatibility * with NetBSD 1.3. */ sdp->swd_ose.ose_inuse = btodb(sdp->swd_npginuse << PAGE_SHIFT); error = copyout(&sdp->swd_ose, sep, sizeof(struct oswapent)); /* now copy out the path if necessary */#if defined(COMPAT_13) if (error == 0 && SCARG(uap, cmd) == SWAP_STATS)#else if (error == 0)#endif error = copyout(sdp->swd_path, &sep->se_path, sdp->swd_pathlen); if (error) goto out; count++;#if defined(COMPAT_13) if (SCARG(uap, cmd) == SWAP_OSTATS) ((struct oswapent *)sep)++; else#endif sep++; } } UVMHIST_LOG(pdhist, "<- done SWAP_STATS", 0, 0, 0, 0); *retval = count; error = 0; goto out; } #ifndef OSKIT /* * all other requests require superuser privs. verify. */ if ((error = suser(p->p_ucred, &p->p_acflag))) goto out; if (SCARG(uap, cmd) == SWAP_GETDUMPDEV) { dev_t *devp = (dev_t *)SCARG(uap, arg); error = copyout(&dumpdev, devp, sizeof(dumpdev)); goto out; }#endif /* * at this point we expect a path name in arg. we will * use namei() to gain a vnode reference (vref), and lock * the vnode (VOP_LOCK). * * XXX: a NULL arg means use the root vnode pointer (e.g. for * miniroot) */#ifdef OSKIT vp = (struct vnode*)SCARG(uap, arg); /* kill const */#else if (SCARG(uap, arg) == NULL) { vp = rootvp; /* miniroot */ if (vget(vp, LK_EXCLUSIVE)) { error = EBUSY; goto out; } if (SCARG(uap, cmd) == SWAP_ON && copystr("miniroot", userpath, sizeof userpath, &len)) panic("swapctl: miniroot copy failed"); } else { int space; char *where; if (SCARG(uap, cmd) == SWAP_ON) { if ((error = copyinstr(SCARG(uap, arg), userpath, sizeof userpath, &len))) goto out; space = UIO_SYSSPACE; where = userpath; } else { space = UIO_USERSPACE; where = (char *)SCARG(uap, arg); } NDINIT(&nd, LOOKUP, FOLLOW|LOCKLEAF, space, where, p); if ((error = namei(&nd))) goto out; vp = nd.ni_vp; }#endif /*OSKIT*/ /* note: "vp" is referenced and locked */ error = 0; /* assume no error */ switch(SCARG(uap, cmd)) {#ifndef OSKIT case SWAP_DUMPDEV: if (vp->v_type != VBLK) { error = ENOTBLK; goto out; } dumpdev = vp->v_rdev; break;#endif case SWAP_CTL: /* * get new priority, remove old entry (if any) and then * reinsert it in the correct place. finally, prune out * any empty priority structures. */ priority = SCARG(uap, misc); spp = malloc(sizeof *spp, M_VMSWAP, M_WAITOK); simple_lock(&uvm.swap_data_lock); if ((sdp = swaplist_find(vp, 1)) == NULL) { error = ENOENT; } else { swaplist_insert(sdp, spp, priority); swaplist_trim(); } simple_unlock(&uvm.swap_data_lock); if (error) free(spp, M_VMSWAP); break; case SWAP_ON: /* * check for duplicates. if none found, then insert a * dummy entry on the list to prevent someone else from * trying to enable this device while we are working on * it. */ priority = SCARG(uap, misc); simple_lock(&uvm.swap_data_lock); if ((sdp = swaplist_find(vp, 0)) != NULL) { error = EBUSY; simple_unlock(&uvm.swap_data_lock); break; } sdp = malloc(sizeof *sdp, M_VMSWAP, M_WAITOK); spp = malloc(sizeof *spp, M_VMSWAP, M_WAITOK); memset(sdp, 0, sizeof(*sdp)); sdp->swd_flags = SWF_FAKE; /* placeholder only */ sdp->swd_vp = vp; sdp->swd_dev = (vp->v_type == VBLK) ? vp->v_rdev : NODEV; BUFQ_INIT(&sdp->swd_tab);#ifdef OSKIT pthread_mutex_init(&sdp->swd_lock, NULL);#endif /* * XXX Is NFS elaboration necessary? */ if (vp->v_type == VREG) { sdp->swd_cred = crdup(p->p_ucred); } swaplist_insert(sdp, spp, priority); simple_unlock(&uvm.swap_data_lock);#ifndef OSKIT sdp->swd_pathlen = len; sdp->swd_path = malloc(sdp->swd_pathlen, M_VMSWAP, M_WAITOK); if (copystr(userpath, sdp->swd_path, sdp->swd_pathlen, 0) != 0) panic("swapctl: copystr");#endif /* * we've now got a FAKE placeholder in the swap list. * now attempt to enable swap on it. if we fail, undo * what we've done and kill the fake entry we just inserted. * if swap_on is a success, it will clear the SWF_FAKE flag */ if ((error = swap_on(p, sdp)) != 0) { simple_lock(&uvm.swap_data_lock); (void) swaplist_find(vp, 1); /* kill fake entry */ swaplist_trim(); simple_unlock(&uvm.swap_data_lock); if (vp->v_type == VREG) { crfree(sdp->swd_cred); }#ifdef OSKIT pthread_mutex_destroy(&sdp->swd_lock);#endif free(sdp->swd_path, M_VMSWAP); free(sdp, M_VMSWAP); break; } break; case SWAP_OFF: simple_lock(&uvm.swap_data_lock); if ((sdp = swaplist_find(vp, 0)) == NULL) { simple_unlock(&uvm.swap_data_lock); error = ENXIO; break; } /* * If a device isn't in use or enabled, we * can't stop swapping from it (again). */ if ((sdp->swd_flags & (SWF_INUSE|SWF_ENABLE)) == 0) { simple_unlock(&uvm.swap_data_lock); error = EBUSY; break; } /* * do the real work. */ if ((error = swap_off(p, sdp)) != 0) goto out; break; default: error = EINVAL; } /* * done! release the ref gained by namei() and unlock. */ vput(vp);out: lockmgr(&swap_syscall_lock, LK_RELEASE, NULL); UVMHIST_LOG(pdhist, "<- done! error=%d", error, 0, 0, 0); return (error);}/* * swap_on: attempt to enable a swapdev for swapping. note that the * swapdev is already on the global list, but disabled (marked * SWF_FAKE). * * => we avoid the start of the disk (to protect disk labels) * => we also avoid the miniroot, if we are swapping to root. * => caller should leave uvm.swap_data_lock unlocked, we may lock it * if needed. */static intswap_on(p, sdp) struct proc *p; struct swapdev *sdp;{ static int count = 0; /* static */ struct vnode *vp; int error, npages, nblocks, size; long addr; struct vattr va;#ifdef NFS extern int (**nfsv2_vnodeop_p) __P((void *));#endif /* NFS */ dev_t dev; char *name; UVMHIST_FUNC("swap_on"); UVMHIST_CALLED(pdhist); /* * we want to enable swapping on sdp. the swd_vp contains * the vnode we want (locked and ref'd), and the swd_dev * contains the dev_t of the file, if it a block device. */ vp = sdp->swd_vp; dev = sdp->swd_dev;#ifndef OSKIT /* * open the swap file (mostly useful for block device files to * let device driver know what is up). * * we skip the open/close for root on swap because the root * has already been opened when root was mounted (mountroot). */ if (vp != rootvp) { if ((error = VOP_OPEN(vp, FREAD|FWRITE, p->p_ucred, p))) return (error); }#endif /* XXX this only works for block devices */ UVMHIST_LOG(pdhist, " dev=%d, major(dev)=%d", dev, major(dev), 0,0); /* * we now need to determine the size of the swap area. for * block specials we can call the d_psize function. * for normal files, we must stat [get attrs]. * * we put the result in nblks. * for normal files, we also want the filesystem block size * (which we get with statfs). */ switch (vp->v_type) { case VBLK: if (bdevsw[major(dev)].d_psize == 0 || (nblocks = (*bdevsw[major(dev)].d_psize)(dev)) == -1) { error = ENXIO; goto bad; } break; case VREG:#ifdef OSKIT#undef VOP_GETATTR#undef VFS_STATFS#define VOP_GETATTR(vp, va, cred, p) oskit_uvm_vop_getattr(vp, va)#define VFS_STATFS(mount, stat, p) oskit_uvm_vfs_statfs(vp, stat)#endif if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p))) goto bad; nblocks = (int)btodb(va.va_size); if ((error = VFS_STATFS(vp->v_mount, &vp->v_mount->mnt_stat, p)) != 0) goto bad; sdp->swd_bsize = vp->v_mount->mnt_stat.f_iosize; /* * limit the max # of outstanding I/O requests we issue * at any one time. take it easy on NFS servers. */#ifdef NFS if (vp->v_op == nfsv2_vnodeop_p) sdp->swd_maxactive = 2; /* XXX */ else#endif /* NFS */ sdp->swd_maxactive = 8; /* XXX */ break; default: error = ENXIO; goto bad; } /* * save nblocks in a safe place and convert to pages. */ sdp->swd_ose.ose_nblks = nblocks; npages = dbtob((u_int64_t)nblocks) >> PAGE_SHIFT; /* * for block special files, we want to make sure that leave * the disklabel and bootblocks alone, so we arrange to skip * over them (arbitrarily choosing to skip PAGE_SIZE bytes). * note that because of this the "size" can be less than the * actual number of blocks on the device. */ if (vp->v_type == VBLK) { /* we use pages 1 to (size - 1) [inclusive] */ size = npages - 1; addr = 1; } else { /* we use pages 0 to (size - 1) [inclusive] */ size = npages; addr = 0; } /* * make sure we have enough blocks for a reasonable sized swap * area. we want at least one page. */ if (size < 1) { UVMHIST_LOG(pdhist, " size <= 1!!", 0, 0, 0, 0); error = EINVAL; goto bad; } UVMHIST_LOG(pdhist, " dev=%x: size=%d addr=%ld\n", dev, size, addr, 0); /* * now we need to allocate an extent to manage this swap device */ name = malloc(12, M_VMSWAP, M_WAITOK); sprintf(name, "swap0x%04x", count++); /* note that extent_create's 3rd arg is inclusive, thus "- 1" */ sdp->swd_ex = extent_create(name, 0, npages - 1, M_VMSWAP,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?