/* * Called for fsync(). * * Since for now the buffer cache can't sync just one file, sync the * whole fs. This is lame. * * Locking: gets/releases vnode lock. (XXX: really?) */ static int sfs_fsync(struct vnode *v) { struct sfs_vnode *sv = v->vn_data; return FSOP_SYNC(sv->sv_absvn.vn_fs); }
/* * Unmount a filesystem/device by name. * First calls FSOP_SYNC on the filesystem; then calls FSOP_UNMOUNT. */ int vfs_unmount(const char *devname) { struct knowndev *kd; int result; vfs_biglock_acquire(); result = findmount(devname, &kd); if (result) { goto fail; } if (kd->kd_fs == NULL) { result = EINVAL; goto fail; } KASSERT(kd->kd_rawname != NULL); KASSERT(kd->kd_device != NULL); /* sync the fs */ result = FSOP_SYNC(kd->kd_fs); if (result) { goto fail; } result = FSOP_UNMOUNT(kd->kd_fs); if (result) { goto fail; } kprintf("vfs: Unmounted %s:\n", kd->kd_name); /* now drop the filesystem */ kd->kd_fs = NULL; KASSERT(result==0); fail: vfs_biglock_release(); return result; }
/* * Global sync function - call FSOP_SYNC on all devices. */ int vfs_sync(void) { struct knowndev *dev; unsigned i, num; vfs_biglock_acquire(); num = knowndevarray_num(knowndevs); for (i=0; i<num; i++) { dev = knowndevarray_get(knowndevs, i); if (dev->kd_fs != NULL) { /*result =*/ FSOP_SYNC(dev->kd_fs); } } vfs_biglock_release(); return 0; }
// Gets the next physical block available for journal and sets jnl->current // Must hold the journal lock static int jnl_next_block(struct journal *jnl) { int err; KASSERT(lock_do_i_hold(jnl->jnl_lock)); daddr_t next_current = jnl->jnl_current + 1; daddr_t next_block = jnl->jnl_base + next_current; daddr_t next_base = jnl->jnl_base; if (next_block >= jnl->jnl_top || next_current >= MAX_JNLBLKS) { err = jnl_sync(jnl); if (err) return err; return 0; } // We've hit our checkpoint so next block is unavailable // In this case, flush all the file system buffers while (next_block == jnl->jnl_checkpoint) { lock_release(jnl->jnl_lock); err = FSOP_SYNC(jnl->jnl_fs); if (err) { lock_acquire(jnl->jnl_lock); return err; } lock_acquire(jnl->jnl_lock); } jnl->jnl_base = next_base; jnl->jnl_current = next_current; return 0; }
/* * Global unmount function. */ int vfs_unmountall(void) { struct knowndev *dev; unsigned i, num; int result; vfs_biglock_acquire(); num = knowndevarray_num(knowndevs); for (i=0; i<num; i++) { dev = knowndevarray_get(knowndevs, i); if (dev->kd_rawname == NULL) { /* not mountable/unmountable */ continue; } if (dev->kd_fs == NULL) { /* not mounted */ continue; } kprintf("vfs: Unmounting %s:\n", dev->kd_name); result = FSOP_SYNC(dev->kd_fs); if (result) { kprintf("vfs: Warning: sync failed for %s: %s, trying " "again\n", dev->kd_name, strerror(result)); result = FSOP_SYNC(dev->kd_fs); if (result) { kprintf("vfs: Warning: sync failed second time" " for %s: %s, giving up...\n", dev->kd_name, strerror(result)); /* * Do not attempt to complete the * unmount as it will likely explode. */ continue; } } result = FSOP_UNMOUNT(dev->kd_fs); if (result == EBUSY) { kprintf("vfs: Cannot unmount %s: (busy)\n", dev->kd_name); continue; } if (result) { kprintf("vfs: Warning: unmount failed for %s:" " %s, already synced, dropping...\n", dev->kd_name, strerror(result)); continue; } /* now drop the filesystem */ dev->kd_fs = NULL; } vfs_biglock_release(); return 0; }
int sfs_jnlmount(struct sfs_fs *sfs, uint64_t txnid_next, daddr_t checkpoint) { struct journal *jnl = kmalloc(sizeof(struct journal)); if (jnl == NULL) return ENOMEM; jnl->jnl_lock = lock_create("SFS Journal Lock"); if (jnl->jnl_lock == NULL) { kfree(jnl); return ENOMEM; } jnl->jnl_txnqueue = transactionarray_create(); if (jnl->jnl_txnqueue == NULL) { lock_destroy(jnl->jnl_lock); kfree(jnl); return ENOMEM; } // Set other fields jnl->jnl_fs = &sfs->sfs_absfs; jnl->jnl_bottom = SFS_JNLSTART(sfs->sfs_super.sp_nblocks); jnl->jnl_top = jnl->jnl_bottom + SFS_JNLSIZE(sfs->sfs_super.sp_nblocks); // set default values jnl->jnl_txnid_next = txnid_next; jnl->jnl_checkpoint = checkpoint; if (!sfs->sfs_super.sp_clean) { // need recovery int err = sfs_recover(sfs, &jnl->jnl_checkpoint, &jnl->jnl_txnid_next); if (err) { transactionarray_destroy(jnl->jnl_txnqueue); lock_destroy(jnl->jnl_lock); kfree(jnl); return err; } // so that FSOP_SYNC will not try to sync the journal sfs->sfs_jnl = NULL; // sync the changes to disk err = FSOP_SYNC(&sfs->sfs_absfs); if (err) { transactionarray_destroy(jnl->jnl_txnqueue); lock_destroy(jnl->jnl_lock); kfree(jnl); return err; } // update the superblock sfs->sfs_super.sp_ckpoint = jnl->jnl_checkpoint; sfs->sfs_super.sp_txnid = jnl->jnl_txnid_next; sfs->sfs_superdirty = true; err = sfs_writesuper(sfs); if (err) { transactionarray_destroy(jnl->jnl_txnqueue); lock_destroy(jnl->jnl_lock); kfree(jnl); return err; } } jnl->jnl_base = jnl->jnl_checkpoint; jnl->jnl_current = 0; jnl->jnl_blkoffset = 0; sfs->sfs_jnl = jnl; return 0; }