diff --git a/kern/arch/mips/vm/dumbvm.c b/kern/arch/mips/vm/dumbvm.c index 1b2e6cd..200a671 100644 --- a/kern/arch/mips/vm/dumbvm.c +++ b/kern/arch/mips/vm/dumbvm.c @@ -135,12 +135,6 @@ coremap_used_bytes() { return 0; } -void -vm_tlbshootdown_all(void) -{ - panic("dumbvm tried to do tlb shootdown?!\n"); -} - void vm_tlbshootdown(const struct tlbshootdown *ts) { diff --git a/kern/include/cpu.h b/kern/include/cpu.h index 787c6cf..d628688 100644 --- a/kern/include/cpu.h +++ b/kern/include/cpu.h @@ -75,24 +75,21 @@ struct cpu { * Accessed by other cpus. * Protected by the IPI lock. * - * If c_numshootdown is -1 (TLBSHOOTDOWN_ALL), all mappings - * should be invalidated. This is used if more than - * TLBSHOOTDOWN_MAX mappings are going to be invalidated at - * once. TLBSHOOTDOWN_MAX is MD and chosen based on when it - * becomes more efficient just to flush the whole TLB. + * TLB shootdown requests made to this CPU are queued in + * c_shootdown[], with c_numshootdown holding the number of + * requests. TLBSHOOTDOWN_MAX is the maximum number that can + * be queued at once, which is machine-dependent. * - * struct tlbshootdown is machine-dependent and might - * reasonably be either an address space and vaddr pair, or a - * paddr, or something else. + * The contents of struct tlbshootdown are also machine- + * dependent and might reasonably be either an address space + * and vaddr pair, or a paddr, or something else. */ uint32_t c_ipi_pending; /* One bit for each IPI number */ struct tlbshootdown c_shootdown[TLBSHOOTDOWN_MAX]; - int c_numshootdown; + unsigned c_numshootdown; struct spinlock c_ipi_lock; }; -#define TLBSHOOTDOWN_ALL (-1) - /* * Initialization functions. * diff --git a/kern/include/version.h b/kern/include/version.h index 532d7ec..43f66be 100644 --- a/kern/include/version.h +++ b/kern/include/version.h @@ -34,7 +34,7 @@ * Leave this alone, so we can tell what version of the OS/161 base * code we gave you. */ -#define BASE_VERSION "2.0.1" +#define BASE_VERSION "2.0.2" /* * Change this as you see fit in the course of hacking the system. diff --git a/kern/include/vfs.h b/kern/include/vfs.h index 77b0dc7..b4a6cc3 100644 --- a/kern/include/vfs.h +++ b/kern/include/vfs.h @@ -156,6 +156,13 @@ int vfs_getcwd(struct uio *buf); * vfs_unmount - Unmount the filesystem presently mounted on the * specified device. * + * vfs_swapon - Look up DEVNAME and mark it as a swap device, + * returning a vnode. Similar to vfs_mount. + * + * vfs_swapoff - Unmark DEVNAME as a swap device. The vnode + * previously returned by vfs_swapon should be + * decref'd first. Similar to vfs_unmount. + * * vfs_unmountall - Unmount all mounted filesystems. */ @@ -172,6 +179,8 @@ int vfs_mount(const char *devname, void *data, struct device *dev, struct fs **result)); int vfs_unmount(const char *devname); +int vfs_swapon(const char *devname, struct vnode **result); +int vfs_swapoff(const char *devname); int vfs_unmountall(void); /* diff --git a/kern/include/vm.h b/kern/include/vm.h index a783f33..6140252 100644 --- a/kern/include/vm.h +++ b/kern/include/vm.h @@ -63,7 +63,6 @@ void free_kpages(vaddr_t addr); unsigned int coremap_used_bytes(void); /* TLB shootdown handling called from interprocessor_interrupt */ -void vm_tlbshootdown_all(void); void vm_tlbshootdown(const struct tlbshootdown *); diff --git a/kern/thread/thread.c b/kern/thread/thread.c index 8ceeaf5..36e7e24 100644 --- a/kern/thread/thread.c +++ b/kern/thread/thread.c @@ -478,7 +478,7 @@ thread_make_runnable(struct thread *target, bool already_have_lock) target->t_state = S_READY; threadlist_addtail(&targetcpu->c_runqueue, target); - if (targetcpu->c_isidle) { + if (targetcpu->c_isidle && targetcpu != curcpu->c_self) { /* * Other processor is idle; send interrupt to make * sure it unidles. @@ -1139,6 +1139,9 @@ ipi_send(struct cpu *target, int code) spinlock_release(&target->c_ipi_lock); } +/* + * Send an IPI to all CPUs. + */ void ipi_broadcast(int code) { @@ -1153,16 +1156,28 @@ ipi_broadcast(int code) } } +/* + * Send a TLB shootdown IPI to the specified CPU. + */ void ipi_tlbshootdown(struct cpu *target, const struct tlbshootdown *mapping) { - int n; + unsigned n; spinlock_acquire(&target->c_ipi_lock); n = target->c_numshootdown; if (n == TLBSHOOTDOWN_MAX) { - target->c_numshootdown = TLBSHOOTDOWN_ALL; + /* + * If you have problems with this panic going off, + * consider: (1) increasing the maximum, (2) putting + * logic here to sleep until space appears (may + * interact awkwardly with VM system locking), (3) + * putting logic here to coalesce requests together, + * and/or (4) improving VM system state tracking to + * reduce the number of unnecessary shootdowns. + */ + panic("ipi_tlbshootdown: Too many shootdowns queued\n"); } else { target->c_shootdown[n] = *mapping; @@ -1175,11 +1190,14 @@ ipi_tlbshootdown(struct cpu *target, const struct tlbshootdown *mapping) spinlock_release(&target->c_ipi_lock); } +/* + * Handle an incoming interprocessor interrupt. + */ void interprocessor_interrupt(void) { uint32_t bits; - int i; + unsigned i; spinlock_acquire(&curcpu->c_ipi_lock); bits = curcpu->c_ipi_pending; @@ -1207,13 +1225,13 @@ interprocessor_interrupt(void) */ } if (bits & (1U << IPI_TLBSHOOTDOWN)) { - if (curcpu->c_numshootdown == TLBSHOOTDOWN_ALL) { - vm_tlbshootdown_all(); - } - else { - for (i=0; ic_numshootdown; i++) { - vm_tlbshootdown(&curcpu->c_shootdown[i]); - } + /* + * Note: depending on your VM system locking you might + * need to release the ipi lock while calling + * vm_tlbshootdown. + */ + for (i=0; ic_numshootdown; i++) { + vm_tlbshootdown(&curcpu->c_shootdown[i]); } curcpu->c_numshootdown = 0; } diff --git a/kern/vfs/vfslist.c b/kern/vfs/vfslist.c index 184e622..9cd2f4a 100644 --- a/kern/vfs/vfslist.c +++ b/kern/vfs/vfslist.c @@ -82,6 +82,9 @@ struct knowndev { struct fs *kd_fs; }; +/* A placeholder for kd_fs for devices used as swap */ +#define SWAP_FS ((struct fs *)-1) + DECLARRAY(knowndev, static __UNUSED inline); DEFARRAY(knowndev, static __UNUSED inline); @@ -160,7 +163,7 @@ vfs_sync(void) num = knowndevarray_num(knowndevs); for (i=0; ikd_fs != NULL) { + if (dev->kd_fs != NULL && dev->kd_fs != SWAP_FS) { /*result =*/ FSOP_SYNC(dev->kd_fs); } } @@ -195,7 +198,7 @@ vfs_getroot(const char *devname, struct vnode **ret) * and DEVNAME names the device, return ENXIO. */ - if (kd->kd_fs!=NULL) { + if (kd->kd_fs != NULL && kd->kd_fs != SWAP_FS) { const char *volname; volname = FSOP_GETVOLNAME(kd->kd_fs); @@ -344,7 +347,7 @@ badnames(const char *n1, const char *n2, const char *n3) for (i=0; ikd_fs) { + if (kd->kd_fs != NULL && kd->kd_fs != SWAP_FS) { volname = FSOP_GETVOLNAME(kd->kd_fs); if (samestring3(volname, n1, n2, n3)) { return 1; @@ -542,6 +545,7 @@ vfs_mount(const char *devname, void *data, } KASSERT(fs != NULL); + KASSERT(fs != SWAP_FS); kd->kd_fs = fs; @@ -553,6 +557,59 @@ vfs_mount(const char *devname, void *data, return 0; } +/* + * Like mount, but for attaching swap. Hands back the raw device + * vnode. Unlike mount tolerates a trailing colon on the device name, + * to avoid student-facing confusion. + */ +int +vfs_swapon(const char *devname, struct vnode **ret) +{ + char *myname = NULL; + size_t len; + struct knowndev *kd; + int result; + + len = strlen(devname); + if (len > 0 && devname[len - 1] == ':') { + /* tolerate trailing :, e.g. lhd0: rather than lhd0 */ + myname = kstrdup(devname); + if (myname == NULL) { + return ENOMEM; + } + myname[len - 1] = 0; + devname = myname; + } + + vfs_biglock_acquire(); + + result = findmount(devname, &kd); + if (result) { + goto out; + } + + if (kd->kd_fs != NULL) { + result = EBUSY; + goto out; + } + KASSERT(kd->kd_rawname != NULL); + KASSERT(kd->kd_device != NULL); + + kprintf("vfs: Swap attached to %s\n", kd->kd_name); + + kd->kd_fs = SWAP_FS; + VOP_INCREF(kd->kd_vnode); + *ret = kd->kd_vnode; + + out: + vfs_biglock_release(); + if (myname != NULL) { + kfree(myname); + } + + return result; +} + /* * Unmount a filesystem/device by name. * First calls FSOP_SYNC on the filesystem; then calls FSOP_UNMOUNT. @@ -570,7 +627,7 @@ vfs_unmount(const char *devname) goto fail; } - if (kd->kd_fs == NULL) { + if (kd->kd_fs == NULL || kd->kd_fs == SWAP_FS) { result = EINVAL; goto fail; } @@ -600,6 +657,43 @@ vfs_unmount(const char *devname) return result; } +/* + * Detach swap. Like unmount. + * + * (Provided for completeness; there is no real need to remove swap + * explicitly prior to shutting down, except perhaps when swapping to + * things that themselves want a clean shutdown, like RAIDs.) + */ +int +vfs_swapoff(const char *devname) +{ + struct knowndev *kd; + int result; + + vfs_biglock_acquire(); + + result = findmount(devname, &kd); + if (result) { + goto fail; + } + + if (kd->kd_fs != SWAP_FS) { + result = EINVAL; + goto fail; + } + + kprintf("vfs: Swap detached from %s:\n", kd->kd_name); + + /* drop it */ + kd->kd_fs = NULL; + + KASSERT(result==0); + + fail: + vfs_biglock_release(); + return result; +} + /* * Global unmount function. */ @@ -623,6 +717,11 @@ vfs_unmountall(void) /* not mounted */ continue; } + if (dev->kd_fs == SWAP_FS) { + /* just drop it */ + dev->kd_fs = NULL; + continue; + } kprintf("vfs: Unmounting %s:\n", dev->kd_name); diff --git a/kern/vfs/vnode.c b/kern/vfs/vnode.c index 374c300..7322707 100644 --- a/kern/vfs/vnode.c +++ b/kern/vfs/vnode.c @@ -129,7 +129,8 @@ vnode_decref(struct vnode *vn) void vnode_check(struct vnode *v, const char *opstr) { - vfs_biglock_acquire(); + /* not safe, and not really needed to check constant fields */ + /*vfs_biglock_acquire();*/ if (v == NULL) { panic("vnode_check: vop_%s: null vnode\n", opstr); @@ -173,5 +174,5 @@ vnode_check(struct vnode *v, const char *opstr) } spinlock_release(&v->vn_countlock); - vfs_biglock_release(); + /*vfs_biglock_release();*/ } diff --git a/mk/os161.config.mk b/mk/os161.config.mk index b77fcc6..653d864 100644 --- a/mk/os161.config.mk +++ b/mk/os161.config.mk @@ -96,7 +96,7 @@ # the build. Default is $(WORKDIR)/tooldir. # # INSTALLTOP Staging directory for installation. -# Default is $(WORKDIR)/install +# Default is $(WORKDIR)/install. # # Probably the only reason to change these would be if you're short on # diskspace in $(WORKDIR). diff --git a/mk/os161.man.mk b/mk/os161.man.mk index 4e07b00..7fde2c6 100644 --- a/mk/os161.man.mk +++ b/mk/os161.man.mk @@ -55,10 +55,13 @@ installmanpages: cp $(_F_) $(OSTREE)$(MANDIR)/$(_F_) .endfor +# clean: remove build products (nothing to do) +clean-local: ; # Mark targets that don't represent files PHONY, to prevent various # lossage if files by those names appear. .PHONY: all all-local install-staging-local install-local installmanpages +.PHONY: clean-local # Finally, get the shared definitions for the most basic rules. .include "$(TOP)/mk/os161.baserules.mk" diff --git a/userland/testbin/multiexec/multiexec.c b/userland/testbin/multiexec/multiexec.c index cdd1854..2eb7931 100644 --- a/userland/testbin/multiexec/multiexec.c +++ b/userland/testbin/multiexec/multiexec.c @@ -174,8 +174,11 @@ spawn(int njobs) for (i=0; i