Пример #1
0
/*
 * Delete a file.
 */
static
int
sfs_remove(struct vnode *dir, const char *name)
{
	struct sfs_vnode *sv = dir->vn_data;
	struct sfs_vnode *victim;
	int slot;
	int result;

	vfs_biglock_acquire();

	/* Look for the file and fetch a vnode for it. */
	result = sfs_lookonce(sv, name, &victim, &slot);
	if (result) {
		vfs_biglock_release();
		return result;
	}

	/* Erase its directory entry. */
	result = sfs_dir_unlink(sv, slot);
	if (result==0) {
		/* If we succeeded, decrement the link count. */
		KASSERT(victim->sv_i.sfi_linkcount > 0);
		victim->sv_i.sfi_linkcount--;
		victim->sv_dirty = true;
	}

	/* Discard the reference that sfs_lookonce got us */
	VOP_DECREF(&victim->sv_v);

	vfs_biglock_release();
	return result;
}
Пример #2
0
/*
 * Unmount code.
 *
 * VFS calls FS_SYNC on the filesystem prior to unmounting it.
 */
static
int
sfs_unmount(struct fs *fs)
{
	struct sfs_fs *sfs = fs->fs_data;

	vfs_biglock_acquire();

	/* Do we have any files open? If so, can't unmount. */
	if (vnodearray_num(sfs->sfs_vnodes) > 0) {
		vfs_biglock_release();
		return EBUSY;
	}

	/* We should have just had sfs_sync called. */
	KASSERT(sfs->sfs_superdirty == false);
	KASSERT(sfs->sfs_freemapdirty == false);

	/* Once we start nuking stuff we can't fail. */
	vnodearray_destroy(sfs->sfs_vnodes);
	bitmap_destroy(sfs->sfs_freemap);

	/* The vfs layer takes care of the device for us */
	(void)sfs->sfs_device;

	/* Destroy the fs object */
	kfree(sfs);

	/* nothing else to do */
	vfs_biglock_release();
	return 0;
}
Пример #3
0
/*
 * Make a hard link to a file.
 * The VFS layer should prevent this being called unless both
 * vnodes are ours.
 */
static
int
sfs_link(struct vnode *dir, const char *name, struct vnode *file)
{
	struct sfs_vnode *sv = dir->vn_data;
	struct sfs_vnode *f = file->vn_data;
	int result;

	KASSERT(file->vn_fs == dir->vn_fs);

	vfs_biglock_acquire();

	/* Just create a link */
	result = sfs_dir_link(sv, name, f->sv_ino, NULL);
	if (result) {
		vfs_biglock_release();
		return result;
	}

	/* and update the link count, marking the inode dirty */
	f->sv_i.sfi_linkcount++;
	f->sv_dirty = true;

	vfs_biglock_release();
	return 0;
}
Пример #4
0
/*
 * lookparent returns the last path component as a string and the
 * directory it's in as a vnode.
 *
 * Since we don't support subdirectories, this is very easy - 
 * return the root dir and copy the path.
 */
static
int
sfs_lookparent(struct vnode *v, char *path, struct vnode **ret,
		  char *buf, size_t buflen)
{
	struct sfs_vnode *sv = v->vn_data;

	vfs_biglock_acquire();

	if (sv->sv_i.sfi_type != SFS_TYPE_DIR) {
		vfs_biglock_release();
		return ENOTDIR;
	}

	if (strlen(path)+1 > buflen) {
		vfs_biglock_release();
		return ENAMETOOLONG;
	}
	strcpy(buf, path);

	VOP_INCREF(&sv->sv_v);
	*ret = &sv->sv_v;

	vfs_biglock_release();
	return 0;
}
Пример #5
0
/*
 * Lookup gets a vnode for a pathname.
 *
 * Since we don't support subdirectories, it's easy - just look up the
 * name.
 */
static
int
sfs_lookup(struct vnode *v, char *path, struct vnode **ret)
{
	struct sfs_vnode *sv = v->vn_data;
	struct sfs_vnode *final;
	int result;

	vfs_biglock_acquire();

	if (sv->sv_i.sfi_type != SFS_TYPE_DIR) {
		vfs_biglock_release();
		return ENOTDIR;
	}
	
	result = sfs_lookonce(sv, path, &final, NULL);
	if (result) {
		vfs_biglock_release();
		return result;
	}

	*ret = &final->sv_v;

	vfs_biglock_release();
	return 0;
}
Пример #6
0
/*
 * VOP_RECLAIM
 *
 * Reclaim should make an effort to returning errors other than EBUSY.
 */
static
int
emufs_reclaim(struct vnode *v)
{
    struct emufs_vnode *ev = v->vn_data;
    struct emufs_fs *ef = v->vn_fs->fs_data;
    unsigned ix, i, num;
    int result;

    /*
     * Need both of these locks, e_lock to protect the device
     * and vfs_biglock to protect the fs-related material.
     */

    vfs_biglock_acquire();
    lock_acquire(ef->ef_emu->e_lock);

    if (ev->ev_v.vn_refcount != 1) {
        lock_release(ef->ef_emu->e_lock);
        vfs_biglock_release();
        return EBUSY;
    }

    /* emu_close retries on I/O error */
    result = emu_close(ev->ev_emu, ev->ev_handle);
    if (result) {
        lock_release(ef->ef_emu->e_lock);
        vfs_biglock_release();
        return result;
    }

    num = vnodearray_num(ef->ef_vnodes);
    ix = num;
    for (i=0; i<num; i++) {
        struct vnode *vx;

        vx = vnodearray_get(ef->ef_vnodes, i);
        if (vx == v) {
            ix = i;
            break;
        }
    }
    if (ix == num) {
        panic("emu%d: reclaim vnode %u not in vnode pool\n",
              ef->ef_emu->e_unit, ev->ev_handle);
    }

    vnodearray_remove(ef->ef_vnodes, ix);
    VOP_CLEANUP(&ev->ev_v);

    lock_release(ef->ef_emu->e_lock);
    vfs_biglock_release();

    kfree(ev);
    return 0;
}
Пример #7
0
/*
 * Called for fsync(), and also on filesystem unmount, global sync(),
 * and some other cases.
 */
static
int
sfs_fsync(struct vnode *v)
{
	struct sfs_vnode *sv = v->vn_data;
	int result;

	vfs_biglock_acquire();
	result = sfs_sync_inode(sv);
	vfs_biglock_release();

	return result;
}
Пример #8
0
/*
 * Routine to retrieve the volume name. Filesystems can be referred
 * to by their volume name followed by a colon as well as the name
 * of the device they're mounted on.
 */
static
const char *
sfs_getvolname(struct fs *fs)
{
	struct sfs_fs *sfs = fs->fs_data;
	const char *ret;

	vfs_biglock_acquire();
	ret = sfs->sfs_super.sp_volname;
	vfs_biglock_release();

	return ret;
}
Пример #9
0
/*
 * Called for write(). sfs_io() does the work.
 */
static
int
sfs_write(struct vnode *v, struct uio *uio)
{
	struct sfs_vnode *sv = v->vn_data;
	int result;

	KASSERT(uio->uio_rw==UIO_WRITE);

	vfs_biglock_acquire();
	result = sfs_io(sv, uio);
	vfs_biglock_release();

	return result;
}
Пример #10
0
/*
 * Read a single filename from a directory into a uio.
 *
 */
 int
 sfs_getdirentry(struct vnode *v, struct uio *uio)
 {
 	struct sfs_vnode *sv = v->vn_data;
	struct sfs_dir tsd;
	int nentries = sfs_dir_nentries(sv);
	int result;

	vfs_biglock_acquire();

	while (uio->uio_offset <= nentries) {
		// Read directory entry
		result = sfs_readdir(sv, &tsd, uio->uio_offset);

		if (result) {
			vfs_biglock_release();
			return result;
		}

		if (tsd.sfd_ino != SFS_NOINO) {
			break;
		}

		uio->uio_offset ++;
	}

	// If we still don't have a result, there must be nothing left
	if (tsd.sfd_ino == SFS_NOINO) {
		vfs_biglock_release();
		return ENOMEM;
	}

	/* Ensure null termination, just in case */
	tsd.sfd_name[sizeof(tsd.sfd_name)-1] = 0;

	// Copy results to uio
	result = uiomove(tsd.sfd_name, strlen(tsd.sfd_name), uio);

	if (result) {
		vfs_biglock_release();
		return result;
	}

	uio->uio_offset ++;
 	vfs_biglock_release();
 	return 0;

 }
Пример #11
0
/*
 * Get vnode for the root of the filesystem.
 * The root vnode is always found in block 1 (SFS_ROOT_LOCATION).
 */
struct vnode *
sfs_getroot(struct fs *fs)
{
	struct sfs_fs *sfs = fs->fs_data;
	struct sfs_vnode *sv;
	int result;

	vfs_biglock_acquire();

	result = sfs_loadvnode(sfs, SFS_ROOT_LOCATION, SFS_TYPE_INVAL, &sv);
	if (result) {
		panic("sfs: getroot: Cannot load root vnode\n");
	}

	vfs_biglock_release();

	return &sv->sv_v;
}
Пример #12
0
/*
 * 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;
}
Пример #13
0
/*
 * 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;
}
Пример #14
0
/*
 * Mount a filesystem. Once we've found the device, call MOUNTFUNC to
 * set up the filesystem and hand back a struct fs.
 *
 * The DATA argument is passed through unchanged to MOUNTFUNC.
 */
int
vfs_mount(const char *devname, void *data,
	  int (*mountfunc)(void *data, struct device *, struct fs **ret))
{
	const char *volname;
	struct knowndev *kd;
	struct fs *fs;
	int result;

	vfs_biglock_acquire();

	result = findmount(devname, &kd);
	if (result) {
		vfs_biglock_release();
		return result;
	}

	if (kd->kd_fs != NULL) {
		vfs_biglock_release();
		return EBUSY;
	}
	KASSERT(kd->kd_rawname != NULL);
	KASSERT(kd->kd_device != NULL);

	result = mountfunc(data, kd->kd_device, &fs);
	if (result) {
		vfs_biglock_release();
		return result;
	}

	KASSERT(fs != NULL);

	kd->kd_fs = fs;

	volname = FSOP_GETVOLNAME(fs);
	kprintf("vfs: Mounted %s: on %s\n",
		volname ? volname : kd->kd_name, kd->kd_name);

	vfs_biglock_release();
	return 0;
}
Пример #15
0
int
sfs_getdirentry(struct vnode *v_node, struct uio *user_io)
{
	struct sfs_vnode *s_node = v_node->vn_data;
	struct sfs_dir sdir;

	int offset = user_io->uio_offset;

	vfs_biglock_acquire(); //acquire lock
	
	int nentries = sfs_dir_nentries(s_node);
	if (offset >= nentries) {
		vfs_biglock_release(); //release lock
		return ENOENT; //Error no entry
	}
	
	int result;
	while(1) {
		result = sfs_readdir(s_node, &sdir, user_io->uio_offset);
		if (result) {
			vfs_biglock_release(); //release lock
			return result; //return this result
		}

		if (sdir.sfd_ino == SFS_NOINO) { //if this sdir is the inode # for free dir entry
			offset++;
			if(offset >= nentries) {
				vfs_biglock_release(); //release lock
				return ENOENT; //error no entry
			}
			user_io->uio_offset++;
			continue;
		}
		break;
	}
	result = uiomove(sdir.sfd_name, strlen(sdir.sfd_name), user_io); //get the result
	user_io->uio_offset = offset + 1; //update uio offset
	vfs_biglock_release(); //release lock
	return 0; //and return
}
Пример #16
0
/*
 * Return the type of the file (types as per kern/stat.h)
 */
static
int
sfs_gettype(struct vnode *v, uint32_t *ret)
{
	struct sfs_vnode *sv = v->vn_data;

	vfs_biglock_acquire();

	switch (sv->sv_i.sfi_type) {
	case SFS_TYPE_FILE:
		*ret = S_IFREG;
		vfs_biglock_release();
		return 0;
	case SFS_TYPE_DIR:
		*ret = S_IFDIR;
		vfs_biglock_release();
		return 0;
	}
	panic("sfs: gettype: Invalid inode type (inode %u, type %u)\n",
	      sv->sv_ino, sv->sv_i.sfi_type);
	return EINVAL;
}
Пример #17
0
/*
 * Add a new device to the VFS layer's device table.
 *
 * If "mountable" is set, the device will be treated as one that expects
 * to have a filesystem mounted on it, and a raw device will be created
 * for direct access.
 */
static
int
vfs_doadd(const char *dname, int mountable, struct device *dev, struct fs *fs)
{
	char *name=NULL, *rawname=NULL;
	struct knowndev *kd=NULL;
	struct vnode *vnode=NULL;
	const char *volname=NULL;
	unsigned index;
	int result;

	vfs_biglock_acquire();

	name = kstrdup(dname);
	if (name==NULL) {
		goto nomem;
	}
	if (mountable) {
		rawname = mkrawname(name);
		if (rawname==NULL) {
			goto nomem;
		}
	}

	vnode = dev_create_vnode(dev);
	if (vnode==NULL) {
		goto nomem;
	}

	kd = kmalloc(sizeof(struct knowndev));
	if (kd==NULL) {
		goto nomem;
	}

	kd->kd_name = name;
	kd->kd_rawname = rawname;
	kd->kd_device = dev;
	kd->kd_vnode = vnode;
	kd->kd_fs = fs;

	if (fs!=NULL) {
		volname = FSOP_GETVOLNAME(fs);
	}

	if (badnames(name, rawname, volname)) {
		vfs_biglock_release();
		return EEXIST;
	}

	result = knowndevarray_add(knowndevs, kd, &index);

	if (result == 0 && dev != NULL) {
		/* use index+1 as the device number, so 0 is reserved */
		dev->d_devnumber = index+1;
	}

	vfs_biglock_release();
	return result;

 nomem:

	if (name) {
		kfree(name);
	}
	if (rawname) {
		kfree(rawname);
	}
	if (vnode) {
		kfree(vnode);
	}
	if (kd) {
		kfree(kd);
	}

	vfs_biglock_release();
	return ENOMEM;
}
Пример #18
0
static
int
sfs_domount(void *options, struct device *dev, struct fs **ret)
{
	int result;
	struct sfs_fs *sfs;

	vfs_biglock_acquire();

	/* We don't pass any options through mount */
	(void)options;

	/*
	 * Make sure our on-disk structures aren't messed up
	 */
	KASSERT(sizeof(struct sfs_super)==SFS_BLOCKSIZE);
	KASSERT(sizeof(struct sfs_inode)==SFS_BLOCKSIZE);
	KASSERT(SFS_BLOCKSIZE % sizeof(struct sfs_dir) == 0);

	/*
	 * We can't mount on devices with the wrong sector size.
	 *
	 * (Note: for all intents and purposes here, "sector" and
	 * "block" are interchangeable terms. Technically a filesystem
	 * block may be composed of several hardware sectors, but we
	 * don't do that in sfs.)
	 */
	if (dev->d_blocksize != SFS_BLOCKSIZE) {
		vfs_biglock_release();
		return ENXIO;
	}

	/* Allocate object */
	sfs = kmalloc(sizeof(struct sfs_fs));
	if (sfs==NULL) {
		vfs_biglock_release();
		return ENOMEM;
	}

	/* Allocate array */
	sfs->sfs_vnodes = vnodearray_create();
	if (sfs->sfs_vnodes == NULL) {
		kfree(sfs);
		vfs_biglock_release();
		return ENOMEM;
	}

	/* Set the device so we can use sfs_rblock() */
	sfs->sfs_device = dev;

	/* Load superblock */
	result = sfs_rblock(sfs, &sfs->sfs_super, SFS_SB_LOCATION);
	if (result) {
		vnodearray_destroy(sfs->sfs_vnodes);
		kfree(sfs);
		vfs_biglock_release();
		return result;
	}

	/* Make some simple sanity checks */

	if (sfs->sfs_super.sp_magic != SFS_MAGIC) {
		kprintf("sfs: Wrong magic number in superblock "
			"(0x%x, should be 0x%x)\n",
			sfs->sfs_super.sp_magic,
			SFS_MAGIC);
		vnodearray_destroy(sfs->sfs_vnodes);
		kfree(sfs);
		vfs_biglock_release();
		return EINVAL;
	}

	if (sfs->sfs_super.sp_nblocks > dev->d_blocks) {
		kprintf("sfs: warning - fs has %u blocks, device has %u\n",
			sfs->sfs_super.sp_nblocks, dev->d_blocks);
	}

	/* Ensure null termination of the volume name */
	sfs->sfs_super.sp_volname[sizeof(sfs->sfs_super.sp_volname)-1] = 0;

	/* Load free space bitmap */
	sfs->sfs_freemap = bitmap_create(SFS_FS_BITMAPSIZE(sfs));
	if (sfs->sfs_freemap == NULL) {
		vnodearray_destroy(sfs->sfs_vnodes);
		kfree(sfs);
		vfs_biglock_release();
		return ENOMEM;
	}
	result = sfs_mapio(sfs, UIO_READ);
	if (result) {
		bitmap_destroy(sfs->sfs_freemap);
		vnodearray_destroy(sfs->sfs_vnodes);
		kfree(sfs);
		vfs_biglock_release();
		return result;
	}

	/* Set up abstract fs calls */
	sfs->sfs_absfs.fs_sync = sfs_sync;
	sfs->sfs_absfs.fs_getvolname = sfs_getvolname;
	sfs->sfs_absfs.fs_getroot = sfs_getroot;
	sfs->sfs_absfs.fs_unmount = sfs_unmount;
	sfs->sfs_absfs.fs_data = sfs;

	/* the other fields */
	sfs->sfs_superdirty = false;
	sfs->sfs_freemapdirty = false;

	/* Hand back the abstract fs */
	*ret = &sfs->sfs_absfs;

	vfs_biglock_release();
	return 0;
}
Пример #19
0
static
int
sfs_sync(struct fs *fs)
{
	struct sfs_fs *sfs;
	unsigned i, num;
	int result;

	vfs_biglock_acquire();

	/*
	 * Get the sfs_fs from the generic abstract fs.
	 *
	 * Note that the abstract struct fs, which is all the VFS
	 * layer knows about, is actually a member of struct sfs_fs.
	 * The pointer in the struct fs points back to the top of the
	 * struct sfs_fs - essentially the same object. This can be a
	 * little confusing at first.
	 *
	 * The following diagram may help:
	 *
	 *     struct sfs_fs        <-------------\
     *           :                            |
     *           :   sfs_absfs (struct fs)    |   <------\
     *           :      :                     |          |
     *           :      :  various members    |          |
     *           :      :                     |          |
     *           :      :  fs_data  ----------/          |
     *           :      :                             ...|...
     *           :                                   .  VFS  .
     *           :                                   . layer .
     *           :   other members                    .......
     *           :
     *           :
	 *
	 * This construct is repeated with vnodes and devices and other
	 * similar things all over the place in OS/161, so taking the
	 * time to straighten it out in your mind is worthwhile.
	 */

	sfs = fs->fs_data;

	/* Go over the array of loaded vnodes, syncing as we go. */
	num = vnodearray_num(sfs->sfs_vnodes);
	for (i=0; i<num; i++) {
		struct vnode *v = vnodearray_get(sfs->sfs_vnodes, i);
		VOP_FSYNC(v);
	}

	/* If the free block map needs to be written, write it. */
	if (sfs->sfs_freemapdirty) {
		result = sfs_mapio(sfs, UIO_WRITE);
		if (result) {
			vfs_biglock_release();
			return result;
		}
		sfs->sfs_freemapdirty = false;
	}

	/* If the superblock needs to be written, write it. */
	if (sfs->sfs_superdirty) {
		result = sfs_wblock(sfs, &sfs->sfs_super, SFS_SB_LOCATION);
		if (result) {
			vfs_biglock_release();
			return result;
		}
		sfs->sfs_superdirty = false;
	}

	vfs_biglock_release();
	return 0;
}
Пример #20
0
/*
 * Called for ftruncate() and from sfs_reclaim.
 */
static
int
sfs_truncate(struct vnode *v, off_t len)
{
	/*
	 * I/O buffer for handling the indirect block.
	 *
	 * Note: in real life (and when you've done the fs assignment)
	 * you would get space from the disk buffer cache for this,
	 * not use a static area.
	 */
	static uint32_t idbuf[SFS_DBPERIDB];

	struct sfs_vnode *sv = v->vn_data;
	struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;

	/* Length in blocks (divide rounding up) */
	uint32_t blocklen = DIVROUNDUP(len, SFS_BLOCKSIZE);

	uint32_t i, j, block;
	uint32_t idblock, baseblock, highblock;
	int result;
	int hasnonzero, iddirty;

	KASSERT(sizeof(idbuf)==SFS_BLOCKSIZE);

	vfs_biglock_acquire();

	/*
	 * Go through the direct blocks. Discard any that are
	 * past the limit we're truncating to.
	 */
	for (i=0; i<SFS_NDIRECT; i++) {
		block = sv->sv_i.sfi_direct[i];
		if (i >= blocklen && block != 0) {
			sfs_bfree(sfs, block);
			sv->sv_i.sfi_direct[i] = 0;
			sv->sv_dirty = true;
		}
	}

	/* Indirect block number */
	idblock = sv->sv_i.sfi_indirect;

	/* The lowest block in the indirect block */
	baseblock = SFS_NDIRECT;

	/* The highest block in the indirect block */
	highblock = baseblock + SFS_DBPERIDB - 1;

	if (blocklen < highblock && idblock != 0) {
		/* We're past the proposed EOF; may need to free stuff */

		/* Read the indirect block */
		result = sfs_rblock(sfs, idbuf, idblock);
		if (result) {
			vfs_biglock_release();
			return result;
		}
		
		hasnonzero = 0;
		iddirty = 0;
		for (j=0; j<SFS_DBPERIDB; j++) {
			/* Discard any blocks that are past the new EOF */
			if (blocklen < baseblock+j && idbuf[j] != 0) {
				sfs_bfree(sfs, idbuf[j]);
				idbuf[j] = 0;
				iddirty = 1;
			}
			/* Remember if we see any nonzero blocks in here */
			if (idbuf[j]!=0) {
				hasnonzero=1;
			}
		}

		if (!hasnonzero) {
			/* The whole indirect block is empty now; free it */
			sfs_bfree(sfs, idblock);
			sv->sv_i.sfi_indirect = 0;
			sv->sv_dirty = true;
		}
		else if (iddirty) {
			/* The indirect block is dirty; write it back */
			result = sfs_wblock(sfs, idbuf, idblock);
			if (result) {
				vfs_biglock_release();
				return result;
			}
		}
	}

	/* Set the file size */
	sv->sv_i.sfi_size = len;

	/* Mark the inode dirty */
	sv->sv_dirty = true;

	vfs_biglock_release();
	return 0;
}
Пример #21
0
/*
 * Called when the vnode refcount (in-memory usage count) hits zero.
 *
 * This function should try to avoid returning errors other than EBUSY.
 */
static
int
sfs_reclaim(struct vnode *v)
{
	struct sfs_vnode *sv = v->vn_data;
	struct sfs_fs *sfs = v->vn_fs->fs_data;
	unsigned ix, i, num;
	int result;

	vfs_biglock_acquire();

	/*
	 * Make sure someone else hasn't picked up the vnode since the
	 * decision was made to reclaim it. (You must also synchronize
	 * this with sfs_loadvnode.)
	 */
	if (v->vn_refcount != 1) {

		/* consume the reference VOP_DECREF gave us */
		KASSERT(v->vn_refcount>1);
		v->vn_refcount--;

		vfs_biglock_release();
		return EBUSY;
	}

	/* If there are no on-disk references to the file either, erase it. */
	if (sv->sv_i.sfi_linkcount==0) {
		result = VOP_TRUNCATE(&sv->sv_v, 0);
		if (result) {
			vfs_biglock_release();
			return result;
		}
	}

	/* Sync the inode to disk */
	result = sfs_sync_inode(sv);
	if (result) {
		vfs_biglock_release();
		return result;
	}

	/* If there are no on-disk references, discard the inode */
	if (sv->sv_i.sfi_linkcount==0) {
		sfs_bfree(sfs, sv->sv_ino);
	}

	/* Remove the vnode structure from the table in the struct sfs_fs. */
	num = vnodearray_num(sfs->sfs_vnodes);
	ix = num;
	for (i=0; i<num; i++) {
		struct vnode *v2 = vnodearray_get(sfs->sfs_vnodes, i);
		struct sfs_vnode *sv2 = v2->vn_data;
		if (sv2 == sv) {
			ix = i;
			break;
		}
	}
	if (ix == num) {
		panic("sfs: reclaim vnode %u not in vnode pool\n",
		      sv->sv_ino);
	}
	vnodearray_remove(sfs->sfs_vnodes, ix);

	VOP_CLEANUP(&sv->sv_v);

	vfs_biglock_release();

	/* Release the storage for the vnode structure itself. */
	kfree(sv);

	/* Done */
	return 0;
}
Пример #22
0
/*
 * Create a file. If EXCL is set, insist that the filename not already
 * exist; otherwise, if it already exists, just open it.
 */
static
int
sfs_creat(struct vnode *v, const char *name, bool excl, mode_t mode,
	  struct vnode **ret)
{
	struct sfs_fs *sfs = v->vn_fs->fs_data;
	struct sfs_vnode *sv = v->vn_data;
	struct sfs_vnode *newguy;
	uint32_t ino;
	int result;

	vfs_biglock_acquire();

	/* Look up the name */
	result = sfs_dir_findname(sv, name, &ino, NULL, NULL);
	if (result!=0 && result!=ENOENT) {
		vfs_biglock_release();
		return result;
	}

	/* If it exists and we didn't want it to, fail */
	if (result==0 && excl) {
		vfs_biglock_release();
		return EEXIST;
	}

	if (result==0) {
		/* We got a file; load its vnode and return */
		result = sfs_loadvnode(sfs, ino, SFS_TYPE_INVAL, &newguy);
		if (result) {
			vfs_biglock_release();
			return result;
		}
		*ret = &newguy->sv_v;
		vfs_biglock_release();
		return 0;
	}

	/* Didn't exist - create it */
	result = sfs_makeobj(sfs, SFS_TYPE_FILE, &newguy);
	if (result) {
		vfs_biglock_release();
		return result;
	}

	/* We don't currently support file permissions; ignore MODE */
	(void)mode;

	/* Link it into the directory */
	result = sfs_dir_link(sv, name, newguy->sv_ino, NULL);
	if (result) {
		VOP_DECREF(&newguy->sv_v);
		vfs_biglock_release();
		return result;
	}

	/* Update the linkcount of the new file */
	newguy->sv_i.sfi_linkcount++;

	/* and consequently mark it dirty. */
	newguy->sv_dirty = true;

	*ret = &newguy->sv_v;
	
	vfs_biglock_release();
	return 0;
}
Пример #23
0
/*
 * Function to load a vnode into memory.
 */
static
int
emufs_loadvnode(struct emufs_fs *ef, uint32_t handle, int isdir,
                struct emufs_vnode **ret)
{
    struct vnode *v;
    struct emufs_vnode *ev;
    unsigned i, num;
    int result;

    vfs_biglock_acquire();
    lock_acquire(ef->ef_emu->e_lock);

    num = vnodearray_num(ef->ef_vnodes);
    for (i=0; i<num; i++) {
        v = vnodearray_get(ef->ef_vnodes, i);
        ev = v->vn_data;
        if (ev->ev_handle == handle) {
            /* Found */

            VOP_INCREF(&ev->ev_v);

            lock_release(ef->ef_emu->e_lock);
            vfs_biglock_release();
            *ret = ev;
            return 0;
        }
    }

    /* Didn't have one; create it */

    ev = kmalloc(sizeof(struct emufs_vnode));
    if (ev==NULL) {
        lock_release(ef->ef_emu->e_lock);
        return ENOMEM;
    }

    ev->ev_emu = ef->ef_emu;
    ev->ev_handle = handle;

    result = VOP_INIT(&ev->ev_v, isdir ? &emufs_dirops : &emufs_fileops,
                      &ef->ef_fs, ev);
    if (result) {
        lock_release(ef->ef_emu->e_lock);
        vfs_biglock_release();
        kfree(ev);
        return result;
    }

    result = vnodearray_add(ef->ef_vnodes, &ev->ev_v, NULL);
    if (result) {
        /* note: VOP_CLEANUP undoes VOP_INIT - it does not kfree */
        VOP_CLEANUP(&ev->ev_v);
        lock_release(ef->ef_emu->e_lock);
        vfs_biglock_release();
        kfree(ev);
        return result;
    }

    lock_release(ef->ef_emu->e_lock);
    vfs_biglock_release();

    *ret = ev;
    return 0;
}
Пример #24
0
/*
 * Rename a file.
 *
 * Since we don't support subdirectories, assumes that the two
 * directories passed are the same.
 */
static
int
sfs_rename(struct vnode *d1, const char *n1, 
	   struct vnode *d2, const char *n2)
{
	struct sfs_vnode *sv = d1->vn_data;
	struct sfs_vnode *g1;
	int slot1, slot2;
	int result, result2;

	vfs_biglock_acquire();

	KASSERT(d1==d2);
	KASSERT(sv->sv_ino == SFS_ROOT_LOCATION);

	/* Look up the old name of the file and get its inode and slot number*/
	result = sfs_lookonce(sv, n1, &g1, &slot1);
	if (result) {
		vfs_biglock_release();
		return result;
	}

	/* We don't support subdirectories */
	KASSERT(g1->sv_i.sfi_type == SFS_TYPE_FILE);

	/*
	 * Link it under the new name.
	 *
	 * We could theoretically just overwrite the original
	 * directory entry, except that we need to check to make sure
	 * the new name doesn't already exist; might as well use the
	 * existing link routine.
	 */
	result = sfs_dir_link(sv, n2, g1->sv_ino, &slot2);
	if (result) {
		goto puke;
	}
	
	/* Increment the link count, and mark inode dirty */
	g1->sv_i.sfi_linkcount++;
	g1->sv_dirty = true;

	/* Unlink the old slot */
	result = sfs_dir_unlink(sv, slot1);
	if (result) {
		goto puke_harder;
	}

	/*
	 * Decrement the link count again, and mark the inode dirty again,
	 * in case it's been synced behind our back.
	 */
	KASSERT(g1->sv_i.sfi_linkcount>0);
	g1->sv_i.sfi_linkcount--;
	g1->sv_dirty = true;

	/* Let go of the reference to g1 */
	VOP_DECREF(&g1->sv_v);

	vfs_biglock_release();
	return 0;

 puke_harder:
	/*
	 * Error recovery: try to undo what we already did
	 */
	result2 = sfs_dir_unlink(sv, slot2);
	if (result2) {
		kprintf("sfs: rename: %s\n", strerror(result));
		kprintf("sfs: rename: while cleaning up: %s\n", 
			strerror(result2));
		panic("sfs: rename: Cannot recover\n");
	}
	g1->sv_i.sfi_linkcount--;
 puke:
	/* Let go of the reference to g1 */
	VOP_DECREF(&g1->sv_v);
	vfs_biglock_release();
	return result;
}
Пример #25
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;
}
Пример #26
0
/*
 * VOP_RECLAIM
 *
 * Reclaim should make an effort to returning errors other than EBUSY.
 */
static
int
emufs_reclaim(struct vnode *v)
{
	struct emufs_vnode *ev = v->vn_data;
	struct emufs_fs *ef = v->vn_fs->fs_data;
	unsigned ix, i, num;
	int result;

	/*
	 * Need all of these locks, e_lock to protect the device,
	 * vfs_biglock to protect the fs-related material, and
	 * vn_countlock for the reference count.
	 */

	vfs_biglock_acquire();
	lock_acquire(ef->ef_emu->e_lock);
	spinlock_acquire(&ev->ev_v.vn_countlock);

	if (ev->ev_v.vn_refcount > 1) {
		/* consume the reference VOP_DECREF passed us */
		ev->ev_v.vn_refcount--;

		spinlock_release(&ev->ev_v.vn_countlock);
		lock_release(ef->ef_emu->e_lock);
		vfs_biglock_release();
		return EBUSY;
	}
	KASSERT(ev->ev_v.vn_refcount == 1);

	/*
	 * Since we hold e_lock and are the last ref, nobody can increment
	 * the refcount, so we can release vn_countlock.
	 */
	spinlock_release(&ev->ev_v.vn_countlock);

	/* emu_close retries on I/O error */
	result = emu_close(ev->ev_emu, ev->ev_handle);
	if (result) {
		lock_release(ef->ef_emu->e_lock);
		vfs_biglock_release();
		return result;
	}

	num = vnodearray_num(ef->ef_vnodes);
	ix = num;
	for (i=0; i<num; i++) {
		struct vnode *vx;

		vx = vnodearray_get(ef->ef_vnodes, i);
		if (vx == v) {
			ix = i;
			break;
		}
	}
	if (ix == num) {
		panic("emu%d: reclaim vnode %u not in vnode pool\n",
		      ef->ef_emu->e_unit, ev->ev_handle);
	}

	vnodearray_remove(ef->ef_vnodes, ix);
	vnode_cleanup(&ev->ev_v);

	lock_release(ef->ef_emu->e_lock);
	vfs_biglock_release();

	kfree(ev);
	return 0;
}