Example #1
0
static int tux_add_dirent(struct inode *dir, struct dentry *dentry, struct inode *inode)
{
	int err = __tux_add_dirent(dir, dentry, inode);
	if (!err)
		d_instantiate(dentry, inode);
	return err;
}
Example #2
0
static int tux_add_dirent(struct inode *dir, struct dentry *dentry,
			  struct inode *inode)
{
	if(DEBUG_MODE_K==1)
	{
		printf("\t\t\t\t%25s[K]  %25s  %4d  #in\n",__FILE__,__func__,__LINE__);
	}
	int err = __tux_add_dirent(dir, dentry, inode);
	if (!err)
		d_instantiate(dentry, inode);
	return err;
}
Example #3
0
static int tux3_symlink(struct inode *dir, struct dentry *dentry,
			const char *symname)
{
	if(DEBUG_MODE_K==1)
	{
		printf("\t\t\t\t%25s[K]  %25s  %4d  #in\n",__FILE__,__func__,__LINE__);
	}
	struct tux_iattr iattr = {
		.uid	= current_fsuid(),
		.gid	= current_fsgid(),
		.mode	= S_IFLNK | S_IRWXUGO,
	};

	return __tux3_symlink(dir, dentry, &iattr, symname);
}
#endif /* !__KERNEL__ */

static int tux_del_dirent(struct inode *dir, struct dentry *dentry)
{
	if(DEBUG_MODE_K==1)
	{
		printf("\t\t\t\t%25s[K]  %25s  %4d  #in\n",__FILE__,__func__,__LINE__);
	}
	struct buffer_head *buffer;
	tux_dirent *entry;

	entry = tux_find_dirent(dir, &dentry->d_name, &buffer);
	if (IS_ERR(entry))
		return PTR_ERR(entry);

	return tux_delete_dirent(dir, buffer, entry);
}

static int tux3_unlink(struct inode *dir, struct dentry *dentry)
{
	if(DEBUG_MODE_K==1)
	{
		printf("\t\t\t\t%25s[K]  %25s  %4d  #in\n",__FILE__,__func__,__LINE__);
	}
	struct inode *inode = dentry->d_inode;
	struct sb *sb = tux_sb(inode->i_sb);

	change_begin(sb);
	int err = tux_del_dirent(dir, dentry);
	if (!err) {
		tux3_iattrdirty(inode);
		inode->i_ctime = dir->i_ctime;
		/* FIXME: we shouldn't write inode for i_nlink = 0? */
		inode_dec_link_count(inode);
	}
	change_end(sb);

	return err;
}

static int tux3_rmdir(struct inode *dir, struct dentry *dentry)
{
	if(DEBUG_MODE_K==1)
	{
		printf("\t\t\t\t%25s[K]  %25s  %4d  #in\n",__FILE__,__func__,__LINE__);
	}
	struct sb *sb = tux_sb(dir->i_sb);
	struct inode *inode = dentry->d_inode;
	int err = tux_dir_is_empty(inode);

	if (!err) {
		change_begin(sb);
		err = tux_del_dirent(dir, dentry);
		if (!err) {
			tux3_iattrdirty(inode);
			inode->i_ctime = dir->i_ctime;
			/* FIXME: we need to do this for POSIX? */
			/* inode->i_size = 0; */
			clear_nlink(inode);
			tux3_mark_inode_dirty_sync(inode);

			inode_dec_link_count(dir);
		}
		change_end(sb);
	}
	return err;
}

static int tux3_rename(struct inode *old_dir, struct dentry *old_dentry,
		       struct inode *new_dir, struct dentry *new_dentry)
{
	if(DEBUG_MODE_K==1)
	{
		printf("\t\t\t\t%25s[K]  %25s  %4d  #in\n",__FILE__,__func__,__LINE__);
	}
	struct inode *old_inode = old_dentry->d_inode;
	struct inode *new_inode = new_dentry->d_inode;
	struct sb *sb = tux_sb(old_inode->i_sb);
	struct buffer_head *old_buffer, *new_buffer, *clone;
	tux_dirent *old_entry, *new_entry;
	void *olddata;
	int err, new_subdir = 0;
	unsigned delta;

	old_entry = tux_find_dirent(old_dir, &old_dentry->d_name, &old_buffer);
	if (IS_ERR(old_entry))
		return PTR_ERR(old_entry);

	/* FIXME: is this needed? */
	assert(be64_to_cpu(old_entry->inum) == tux_inode(old_inode)->inum);

	change_begin(sb);
	delta = tux3_get_current_delta();

	if (new_inode) {
		int old_is_dir = S_ISDIR(old_inode->i_mode);
		if (old_is_dir) {
			err = tux_dir_is_empty(new_inode);
			if (err)
				goto error;
		}

		new_entry = tux_find_dirent(new_dir, &new_dentry->d_name,
					    &new_buffer);
		if (IS_ERR(new_entry)) {
			assert(PTR_ERR(new_entry) != -ENOENT);
			err = PTR_ERR(new_entry);
			goto error;
		}

		/*
		 * The directory is protected by i_mutex.
		 * blockdirty() should never return -EAGAIN.
		 */
		olddata = bufdata(new_buffer);
		clone = blockdirty(new_buffer, delta);
		if (IS_ERR(clone)) {
			assert(PTR_ERR(clone) != -EAGAIN);
			blockput(new_buffer);
			err = PTR_ERR(clone);
			goto error;
		}
		new_entry = ptr_redirect(new_entry, olddata, bufdata(clone));

		/* this releases new_buffer */
		tux_update_dirent(new_dir, clone, new_entry, old_inode);

		tux3_iattrdirty(new_inode);
		new_inode->i_ctime = new_dir->i_ctime;
		if (old_is_dir)
			drop_nlink(new_inode);
		inode_dec_link_count(new_inode);
	} else {
		new_subdir = S_ISDIR(old_inode->i_mode) && new_dir != old_dir;
		if (new_subdir) {
			if (new_dir->i_nlink >= TUX_LINK_MAX) {
				err = -EMLINK;
				goto error;
			}
		}
		err = __tux_add_dirent(new_dir, new_dentry, old_inode);
		if (err)
			goto error;
		if (new_subdir)
			inode_inc_link_count(new_dir);
	}
	tux3_iattrdirty(old_inode);
	old_inode->i_ctime = new_dir->i_ctime;
	tux3_mark_inode_dirty(old_inode);

	/*
	 * The new entry can be on same buffer with old_buffer, and
	 * may did buffer fork in the above path. So if old_buffer is
	 * forked buffer, we update the old_buffer in here.
	 */
	if (buffer_forked(old_buffer)) {
		clone = blockget(mapping(old_dir), bufindex(old_buffer));
		assert(clone);
		old_entry = ptr_redirect(old_entry, bufdata(old_buffer),
					 bufdata(clone));
		blockput(old_buffer);
		old_buffer = clone;
	}
	err = tux_delete_dirent(old_dir, old_buffer, old_entry);
	if (err) {
		tux3_fs_error(sb, "couldn't delete old entry (%Lu)",
			      tux_inode(old_inode)->inum);
		/* FIXME: now, we have hardlink even if it's dir. */
		inode_inc_link_count(old_inode);
	}
	if (!err && new_subdir)
		inode_dec_link_count(old_dir);

	change_end(sb);
	return err;

error:
	change_end(sb);
	blockput(old_buffer);
	return err;
}

#ifdef __KERNEL__
const struct file_operations tux_dir_fops = {
	.llseek		= generic_file_llseek,
	.read		= generic_read_dir,
	.readdir	= tux_readdir,
	.fsync		= tux3_sync_file,
};

const struct inode_operations tux_dir_iops = {
	.create		= tux3_create,
	.lookup		= tux3_lookup,
	.link		= tux3_link,
	.unlink		= tux3_unlink,
	.symlink	= tux3_symlink,
	.mkdir		= tux3_mkdir,
	.rmdir		= tux3_rmdir,
	.mknod		= tux3_mknod,
	.rename		= tux3_rename,
	.setattr	= tux3_setattr,
	.getattr	= tux3_getattr
//	.setxattr	= generic_setxattr,
//	.getxattr	= generic_getxattr,
//	.listxattr	= ext3_listxattr,
//	.removexattr	= generic_removexattr,
//	.permission	= ext3_permission,
	/* FIXME: why doesn't ext4 support this for directory? */
//	.fallocate	= ext4_fallocate,
//	.fiemap		= ext4_fiemap,
};
Example #4
0
static int tux3_rename(struct inode *old_dir, struct dentry *old_dentry,
		       struct inode *new_dir, struct dentry *new_dentry)
{
	struct inode *old_inode = old_dentry->d_inode;
	struct inode *new_inode = new_dentry->d_inode;
	struct buffer_head *old_buffer, *new_buffer;
	tux_dirent *old_entry, *new_entry;
	int err, new_subdir = 0;

	old_entry = tux_find_dirent(old_dir, old_dentry->d_name.name,
				    old_dentry->d_name.len, &old_buffer);
	if (IS_ERR(old_entry))
		return PTR_ERR(old_entry);

	/* FIXME: is this needed? */
	BUG_ON(from_be_u64(old_entry->inum) != tux_inode(old_inode)->inum);

	change_begin(tux_sb(old_inode->i_sb));
	if (new_inode) {
		int old_is_dir = S_ISDIR(old_inode->i_mode);
		if (old_is_dir) {
			err = tux_dir_is_empty(new_inode);
			if (err)
				goto error;
		}

		new_entry = tux_find_dirent(new_dir, new_dentry->d_name.name,
					new_dentry->d_name.len, &new_buffer);
		if (IS_ERR(new_entry)) {
			BUG_ON(PTR_ERR(new_entry) == -ENOENT);
			err = PTR_ERR(new_entry);
			goto error;
		}
		/* this releases new_buffer */
		tux_update_dirent(new_buffer, new_entry, old_inode);
		new_inode->i_ctime = new_dir->i_ctime;
		if (old_is_dir)
			drop_nlink(new_inode);
		inode_dec_link_count(new_inode);
	} else {
		new_subdir = S_ISDIR(old_inode->i_mode) && new_dir != old_dir;
		if (new_subdir) {
			if (new_dir->i_nlink >= TUX_LINK_MAX) {
				err = -EMLINK;
				goto error;
			}
		}
		err = __tux_add_dirent(new_dir, new_dentry, old_inode);
		if (err)
			goto error;
		if (new_subdir)
			inode_inc_link_count(new_dir);
	}
	old_inode->i_ctime = new_dir->i_ctime;
	mark_inode_dirty(old_inode);

	err = tux_delete_dirent(old_buffer, old_entry);
	if (err) {
		printk(KERN_ERR "TUX3: %s: couldn't delete old entry (%Lu)\n",
		       __func__, (L)tux_inode(old_inode)->inum);
		/* FIXME: now, we have hardlink even if it's dir. */
		inode_inc_link_count(old_inode);
	}
	if (!err && new_subdir)
		inode_dec_link_count(old_dir);

	change_end(tux_sb(old_inode->i_sb));
	return err;

error:
	change_end(tux_sb(old_inode->i_sb));
	brelse(old_buffer);
	return err;
}