Beispiel #1
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;
}
Beispiel #2
0
/* Setup . and .. in root directory if this is the first mount */
int
sfs_setup_root(struct sfs_fs *sfs)
{
	struct fs *fs = &sfs->sfs_absfs;
	struct vnode *root_vv;
	struct sfs_vnode *root_sv;
	int result;

	root_vv = sfs_getroot(fs);
	root_sv = root_vv->vn_data;

	if(sfs_dir_nentries(root_sv) != 0){
		VOP_DECREF(root_vv);
		return 0;
	}

	result = sfs_dir_link(root_sv, ".", SFS_ROOT_LOCATION, NULL);
        if (result) {
                VOP_DECREF(root_vv);
                return result;
        }

        root_sv->sv_i.sfi_linkcount++;
        root_sv->sv_dirty = 1;

        result = sfs_dir_link(root_sv, "..", SFS_ROOT_LOCATION, NULL);
        if (result) {
                sfs_dir_unlink(root_sv, 0); /* Hope this doesn't fail?? */
                root_sv->sv_i.sfi_linkcount--;
                root_sv->sv_dirty = 1;
                VOP_DECREF(root_vv);
                return result;
        }

        root_sv->sv_i.sfi_linkcount++;
        root_sv->sv_dirty = 1;	

	/* Decrement reference that sfs_getroot incremented */
	VOP_DECREF(root_vv);

	return 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, int excl, struct vnode **ret)
{
	struct sfs_fs *sfs = v->vn_fs->fs_data;
	struct sfs_vnode *sv = v->vn_data;
	struct sfs_vnode *newguy;
	u_int32_t ino;
	int result;

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

	/* If it exists and we didn't want it to, fail */
	if (result==0 && excl) {
		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) {
			return result;
		}
		*ret = &newguy->sv_v;
		return 0;
	}

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

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

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

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

	*ret = &newguy->sv_v;
	
	return 0;
}
Beispiel #4
0
/*
 * Make a hard link to a file.
 * The VFS layer should prevent this being called unless both
 * vnodes are ours.
 *
 * Locking: locks both vnodes, parent first. Since we aren't allowed
 * to hardlink directories, the target can't be an ancestor of the
 * directory we're working in.
 *
 * Requires up to 4 buffers.
 */
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;
	struct sfs_dinode *inodeptr;
	int result;

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

	/* Hard links to directories aren't allowed. */
	if (f->sv_type == SFS_TYPE_DIR) {
		return EINVAL;
	}
	KASSERT(file != dir);

	reserve_buffers(SFS_BLOCKSIZE);

	/* directory must be locked first */
	lock_acquire(sv->sv_lock);
	lock_acquire(f->sv_lock);

	result = sfs_dinode_load(f);
	if (result) {
		lock_release(f->sv_lock);
		lock_release(sv->sv_lock);
		unreserve_buffers(SFS_BLOCKSIZE);
		return result;
	}

	/* Create the link */
	result = sfs_dir_link(sv, name, f->sv_ino, NULL);
	if (result) {
		sfs_dinode_unload(f);
		lock_release(f->sv_lock);
		lock_release(sv->sv_lock);
		unreserve_buffers(SFS_BLOCKSIZE);
		return result;
	}

	/* and update the link count, marking the inode dirty */
	inodeptr = sfs_dinode_map(f);
	inodeptr->sfi_linkcount++;
	sfs_dinode_mark_dirty(f);

	sfs_dinode_unload(f);
	lock_release(f->sv_lock);
	lock_release(sv->sv_lock);
	unreserve_buffers(SFS_BLOCKSIZE);
	return 0;
}
Beispiel #5
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;

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

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

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

	return 0;
}
Beispiel #6
0
static
int
sfs_mkdir(struct vnode *vv, const char *name){
	struct sfs_fs *sfs = vv->vn_fs->fs_data;
        struct sfs_vnode *sv = vv->vn_data;
        struct sfs_vnode *newguy;
        u_int32_t ino;
        int result, result2, slot1, slot2;

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

        if (result==0) {
                /* Directory or file of same name already exists */
                return EINVAL;
        }

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

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

        /* Increment linkcount of the new directory and mark it dirty */
        newguy->sv_i.sfi_linkcount++;
        newguy->sv_dirty = 1;

	/* Link . and .. into our directory */
	result = sfs_dir_link(newguy, ".", newguy->sv_ino, &slot2);
        if (result) {
		result2 = sfs_dir_unlink(sv, slot1);
                if(result2){
			VOP_DECREF(&newguy->sv_v);
			return result2;
		}
		newguy->sv_i.sfi_linkcount--;
        	newguy->sv_dirty = 1;
		VOP_DECREF(&newguy->sv_v);
                return result;
        }

	newguy->sv_i.sfi_linkcount++;
        newguy->sv_dirty = 1;

	result = sfs_dir_link(newguy, "..", sv->sv_ino, NULL);
        if (result) {
		result2 = sfs_dir_unlink(newguy, slot2);
		if(result2){
			VOP_DECREF(&newguy->sv_v);
			return result2;
		}
                newguy->sv_i.sfi_linkcount--; 
                newguy->sv_dirty = 1;
                result2 = sfs_dir_unlink(sv, slot1);
		if(result2){
                        VOP_DECREF(&newguy->sv_v);
                        return result2;
                }
                newguy->sv_i.sfi_linkcount--;
                newguy->sv_dirty = 1;
		VOP_DECREF(&newguy->sv_v);
                return result;
        }

        sv->sv_i.sfi_linkcount++;
        sv->sv_dirty = 1;

	VOP_DECREF(&newguy->sv_v);

	return 0;
}
Beispiel #7
0
/*
 * Rename a file.
 */
static
int
sfs_rename(struct vnode *d1, const char *n1, 
	   struct vnode *d2, const char *n2)
{
	struct sfs_vnode *sv1 = d1->vn_data;
	struct sfs_vnode *sv2 = d2->vn_data;
	struct sfs_vnode *g1;
	int slot1, slot2;
	int result, result2;

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

	/*
	 * Link it to the 'new' directory 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(sv2, 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 = 1;

	/* Unlink the old slot */
	result = sfs_dir_unlink(sv1, 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.
	 */
	assert(g1->sv_i.sfi_linkcount>0);
	g1->sv_i.sfi_linkcount--;
	g1->sv_dirty = 1;

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

	return 0;

 puke_harder:
	/*
	 * Error recovery: try to undo what we already did
	 */
	result2 = sfs_dir_unlink(sv2, 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);
	return result;
}
Beispiel #8
0
/*
 * Delete a directory.
 *
 * Locking: Acquires vnode lock for parent dir and then vnode lock for
 * victim dir. Releases both.
 *
 * Requires 4 buffers.
 */
static
int
sfs_rmdir(struct vnode *v, const char *name)
{
	struct sfs_vnode *sv = v->vn_data;
	struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data;
	struct sfs_vnode *victim;
	struct sfs_dinode *dir_inodeptr;
	struct sfs_dinode *victim_inodeptr;
	int result, result2;
	int slot;

	/* Cannot remove the . or .. entries from a directory! */
	if (!strcmp(name, ".") || !strcmp(name, "..")) {
		return EINVAL;
	}

	lock_acquire(sv->sv_lock);
	reserve_buffers(SFS_BLOCKSIZE);

	result = sfs_dinode_load(sv);
	if (result) {
		goto die_loadsv;
	}
	dir_inodeptr = sfs_dinode_map(sv);

	if (dir_inodeptr->sfi_linkcount == 0) {
		result = ENOENT;
		goto die_linkcount;
	}

	result = sfs_lookonce(sv, name, &victim, &slot);
	if (result) {
		goto die_linkcount;
	}

	lock_acquire(victim->sv_lock);
	result = sfs_dinode_load(victim);
	if (result) {
		goto die_loadvictim;
	}
	victim_inodeptr = sfs_dinode_map(victim);

	if (victim->sv_ino == SFS_ROOTDIR_INO) {
		result = EPERM;
		goto die_total;
	}

	/* Only allowed on directories */
	if (victim_inodeptr->sfi_type != SFS_TYPE_DIR) {
		result = ENOTDIR;
		goto die_total;
	}

	result = sfs_dir_checkempty(victim);
	if (result) {
		goto die_total;
	}

	result = sfs_dir_unlink(sv, slot);
	if (result) {
		goto die_total;
	}

	KASSERT(dir_inodeptr->sfi_linkcount > 1);
	KASSERT(victim_inodeptr->sfi_linkcount==2);

	dir_inodeptr->sfi_linkcount--;
	sfs_dinode_mark_dirty(sv);

	victim_inodeptr->sfi_linkcount -= 2;
	sfs_dinode_mark_dirty(victim);

	result = sfs_itrunc(victim, 0);
	if (result) {
		victim_inodeptr->sfi_linkcount += 2;
		dir_inodeptr->sfi_linkcount++;
		result2 = sfs_dir_link(sv, name, victim->sv_ino, NULL);
		if (result2) {
			/* XXX: would be better if this case didn't exist */
			panic("sfs: %s: rmdir: %s; while recovering: %s\n",
			      sfs->sfs_sb.sb_volname, 
			      strerror(result), strerror(result2));
		}
		goto die_total;
	}

die_total:
	sfs_dinode_unload(victim);
die_loadvictim:
	lock_release(victim->sv_lock);
 	VOP_DECREF(&victim->sv_absvn);
die_linkcount:
	sfs_dinode_unload(sv);
die_loadsv:
 	unreserve_buffers(SFS_BLOCKSIZE);
 	lock_release(sv->sv_lock);

	return result;
}
Beispiel #9
0
static
int
sfs_mkdir(struct vnode *v, const char *name, mode_t mode)
{
	struct sfs_fs *sfs = v->vn_fs->fs_data;
	struct sfs_vnode *sv = v->vn_data;
	int result;
	uint32_t ino;
	struct sfs_dinode *dir_inodeptr;
	struct sfs_dinode *new_inodeptr;
	struct sfs_vnode *newguy;

	(void)mode;

	lock_acquire(sv->sv_lock);
	reserve_buffers(SFS_BLOCKSIZE);

	result = sfs_dinode_load(sv);
	if (result) {
		goto die_early;
	}
	dir_inodeptr = sfs_dinode_map(sv);

	if (dir_inodeptr->sfi_linkcount == 0) {
		result = ENOENT;
		goto die_simple;
	}

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

	/* If it exists, fail */
	if (result==0) {
		result = EEXIST;
		goto die_simple;
	}

	/*
	 * If we're trying to create . or .. and we get this far
	 * (meaning the entry in question is missing), the fs is
	 * corrupted. Let's not make it worse. Best at this point to
	 * bail out and run fsck.
	 */
	if (!strcmp(name, ".") || !strcmp(name, "..")) {
		panic("sfs: %s: No %s entry in dir %u; please fsck\n",
		      sfs->sfs_sb.sb_volname, name, sv->sv_ino);
	}

	result = sfs_makeobj(sfs, SFS_TYPE_DIR, &newguy);
	if (result) {
		goto die_simple;
	}
	new_inodeptr = sfs_dinode_map(newguy);

	result = sfs_dir_link(newguy, ".", newguy->sv_ino, NULL);
	if (result) {
		goto die_uncreate;
	}

	result = sfs_dir_link(newguy, "..", sv->sv_ino, NULL);
	if (result) {
		goto die_uncreate;
	}

	result = sfs_dir_link(sv, name, newguy->sv_ino, NULL);
	if (result) {
		goto die_uncreate;
	}

        /*
         * Increment link counts (Note: not until after the names are
         * added - that way if one fails, the link count will be zero,
         * and reclaim will dispose of the new directory.
         *
         * Note also that the name in the parent directory gets added
         * last, so there's no case in which we have to go back and
         * remove it.
         */

	new_inodeptr->sfi_linkcount += 2;
	dir_inodeptr->sfi_linkcount++;
	sfs_dinode_mark_dirty(newguy);
	sfs_dinode_mark_dirty(sv);

	sfs_dinode_unload(newguy);
	sfs_dinode_unload(sv);
	lock_release(newguy->sv_lock);
	lock_release(sv->sv_lock);
	VOP_DECREF(&newguy->sv_absvn);

	unreserve_buffers(SFS_BLOCKSIZE);

	KASSERT(result==0);
	return result;

die_uncreate:
	sfs_dinode_unload(newguy);
	lock_release(newguy->sv_lock);
	VOP_DECREF(&newguy->sv_absvn);

die_simple:
	sfs_dinode_unload(sv);

die_early:
	unreserve_buffers(SFS_BLOCKSIZE);
	lock_release(sv->sv_lock);
	return result;
}
Beispiel #10
0
/*
 * Create a file. If EXCL is set, insist that the filename not already
 * exist; otherwise, if it already exists, just open it.
 *
 * Locking: Gets/releases the vnode lock for v. Does not lock the new vnode,
 * as nobody else can get to it except by searching the directory it's in,
 * which is locked.
 *
 * Requires up to 4 buffers as VOP_DECREF invocations may take 3.
 */
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;
	struct sfs_dinode *sv_dino;
	struct sfs_dinode *new_dino;
	uint32_t ino;
	int result;

	lock_acquire(sv->sv_lock);
	reserve_buffers(SFS_BLOCKSIZE);

	result = sfs_dinode_load(sv);
	if (result) {
		unreserve_buffers(SFS_BLOCKSIZE);
		lock_release(sv->sv_lock);
		return result;
	}
	sv_dino = sfs_dinode_map(sv);

	if (sv_dino->sfi_linkcount == 0) {
		sfs_dinode_unload(sv);
		unreserve_buffers(SFS_BLOCKSIZE);
		lock_release(sv->sv_lock);
		return ENOENT;
	}

	sfs_dinode_unload(sv);

	/* Look up the name */
	result = sfs_dir_findname(sv, name, &ino, NULL, NULL);
	if (result!=0 && result!=ENOENT) {
		unreserve_buffers(SFS_BLOCKSIZE);
		lock_release(sv->sv_lock);
		return result;
	}

	/* If it exists and we didn't want it to, fail */
	if (result==0 && excl) {
		unreserve_buffers(SFS_BLOCKSIZE);
		lock_release(sv->sv_lock);
		return EEXIST;
	}

	if (result==0) {
		/* We got something; load its vnode and return */
		result = sfs_loadvnode(sfs, ino, SFS_TYPE_INVAL, &newguy);
		if (result) {
			unreserve_buffers(SFS_BLOCKSIZE);
			lock_release(sv->sv_lock);
			return result;
		}

		*ret = &newguy->sv_absvn;
		unreserve_buffers(SFS_BLOCKSIZE);
		lock_release(sv->sv_lock);
		return 0;
	}

	/* Didn't exist - create it */
	result = sfs_makeobj(sfs, SFS_TYPE_FILE, &newguy);
	if (result) {
		unreserve_buffers(SFS_BLOCKSIZE);
		lock_release(sv->sv_lock);
		return result;
	}

	/* sfs_makeobj loads the inode for us */
	new_dino = sfs_dinode_map(newguy);

	/* 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) {
		sfs_dinode_unload(newguy);
		lock_release(newguy->sv_lock);
		VOP_DECREF(&newguy->sv_absvn);
		lock_release(sv->sv_lock);
		unreserve_buffers(SFS_BLOCKSIZE);
		return result;
	}

	/* Update the linkcount of the new file */
	new_dino->sfi_linkcount++;

	/* and consequently mark it dirty. */
	sfs_dinode_mark_dirty(newguy);

	*ret = &newguy->sv_absvn;

	sfs_dinode_unload(newguy);
	unreserve_buffers(SFS_BLOCKSIZE);
	lock_release(newguy->sv_lock);
	lock_release(sv->sv_lock);
	return 0;
}
Beispiel #11
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;
}