Beispiel #1
0
static int tux3_symlink(struct inode *dir, struct dentry *dentry,
			const char *symname)
{
	struct inode *inode;
	int err;

	change_begin(tux_sb(dir->i_sb));
	inode = tux_create_inode(dir, S_IFLNK | S_IRWXUGO, 0);
	err = PTR_ERR(inode);
	if (!IS_ERR(inode)) {
		err = page_symlink(inode, symname, strlen(symname) + 1);
		if (!err) {
			err = tux_add_dirent(dir, dentry, inode);
			if (!err)
				goto out;
		}
		inode_dec_link_count(inode);
		iput(inode);
	}
out:
	change_end(tux_sb(dir->i_sb));
	return err;
}
Beispiel #2
0
static void tux3_write_super(struct super_block *sb)
{
	struct buffer_head *bh;

	BUG_ON(SB_LOC < sb->s_blocksize);
	bh = sb_bread(sb, SB_LOC >> sb->s_blocksize_bits);
	if (!bh) {
		printk(KERN_ERR "TUX3: unable to read superblock\n");
		return;
	}
	pack_sb(tux_sb(sb), bufdata(bh));
	brelse_dirty(bh);
	sb->s_dirt = 0;
}
Beispiel #3
0
/* Modify atom refcount */
static int atomref(struct inode *atable, atom_t atom, int use)
{
	struct sb *sb = tux_sb(atable->i_sb);
	unsigned shift = sb->blockbits - ATOMREF_BLKBITS;
	unsigned block = sb->atomref_base + ATOMREF_SIZE * (atom >> shift);
	unsigned offset = atom & ~(-1 << shift), kill = 0;
	struct buffer_head *buffer;
	__be16 *refcount;
	int err;

	buffer = blockread(mapping(atable), block);
	if (!buffer)
		return -EIO;

	refcount = bufdata(buffer);
	int low = be16_to_cpu(refcount[offset]) + use;
	trace("inc atom %x by %d, offset %x[%x], low = %d",
	      atom, use, block, offset, low);

	/* This releases buffer */
	err = update_refcount(sb, buffer, offset, low);
	if (err)
		return err;

	if (!low || (low & (-1 << 16))) {
		buffer = blockread(mapping(atable), block + 1);
		if (!buffer)
			return -EIO;

		refcount = bufdata(buffer);
		int high = be16_to_cpu(refcount[offset]);
		if (!low)
			blockput(buffer);
		else {
			trace("carry %d, offset %x[%x], high = %d",
			      (low >> 16), block, offset, high);
			high += (low >> 16);
			assert(high >= 0); /* paranoia check */

			/* This releases buffer */
			err = update_refcount(sb, buffer, offset, high);
			if (err) {
				/* FIXME: better set a flag that atomref broke
				 * or something! */
				return err;
			}
		}

		kill = !(low | high);
	}
Beispiel #4
0
static int __tux3_mknod(struct inode *dir, struct dentry *dentry,
			struct tux_iattr *iattr, dev_t rdev)
{
	if(DEBUG_MODE_K==1)
	{
		printf("\t\t\t\t%25s[K]  %25s  %4d  #in\n",__FILE__,__func__,__LINE__);
	}
	struct inode *inode;
	int err, is_dir = S_ISDIR(iattr->mode);

	if (!huge_valid_dev(rdev))
		return -EINVAL;

	if (is_dir && dir->i_nlink >= TUX_LINK_MAX)
		return -EMLINK;

	change_begin(tux_sb(dir->i_sb));
	inode = tux_create_inode(dir, iattr, rdev);
	err = PTR_ERR(inode);
	if (!IS_ERR(inode)) {
		err = tux_add_dirent(dir, dentry, inode);
		if (!err) {
			unlock_new_inode(inode);
			if (is_dir)
				inode_inc_link_count(dir);
			goto out;
		}
		clear_nlink(inode);
		tux3_mark_inode_dirty(inode);
		unlock_new_inode(inode);
		iput(inode);
	}
out:
	change_end(tux_sb(dir->i_sb));
	return err;
}
Beispiel #5
0
static void tux3_put_super(struct super_block *sb)
{
	struct sb *sbi = tux_sb(sb);

	/* FIXME: remove this, then use sb->s_dirt instead */
	tux3_write_super(sb);

	empty_stash(&sbi->defree);
	iput(sbi->atable);
	iput(sbi->bitmap);
	iput(sbi->volmap);
	iput(sbi->logmap);

	sb->s_fs_info = NULL;
	kfree(sbi);
}
Beispiel #6
0
/* Convert atom to name */
static int unatom(struct inode *atable, atom_t atom, char *name, unsigned size)
{
	if(DEBUG_MODE_K==1)
	{
		printf("\t\t\t\t%25s[K]  %25s  %4d  #in\n",__FILE__,__func__,__LINE__);
	}
	struct sb *sb = tux_sb(atable->i_sb);
	struct buffer_head *buffer;
	int err;

	loff_t where = unatom_dict_read(atable, atom);
	if (where < 0) {
		err = where;
		goto error;
	}

	buffer = blockread(mapping(atable), where >> sb->blockbits);
	if (!buffer) {
		err = -EIO;
		goto error;
	}
	tux_dirent *entry = bufdata(buffer) + (where & sb->blockmask);
	if (entry_atom(entry) != atom) {
		tux3_fs_error(sb, "atom %x reverse entry broken", atom);
		err = -EIO;
		goto error_blockput;
	}
	unsigned len = entry->name_len;
	if (size) {
		if (len > size) {
			err = -ERANGE;
			goto error_blockput;
		}
		memcpy(name, entry->name, len);
	}
	blockput(buffer);

	return len;

error_blockput:
	blockput(buffer);
error:
	return err;
}
Beispiel #7
0
/* Find atom of name */
static int find_atom(struct inode *atable, const char *name, unsigned len,
		     atom_t *atom)
{
	struct sb *sb = tux_sb(atable->i_sb);
	struct buffer_head *buffer;
	struct tux3_dirent *entry;

	entry = tux_find_entry(atable, name, len, &buffer, sb->atomdictsize);
	if (IS_ERR(entry)) {
		int err = PTR_ERR(entry);
		if (err == -ENOENT)
			return -ENODATA;
		return err;
	}

	*atom = entry_atom(entry);
	blockput(buffer);
	return 0;
}
/*
 * Mark inode dirty to delete. (called from ->drop_inode()).
 * Caller must hold inode->i_lock.
 */
void tux3_mark_inode_to_delete(struct inode *inode)
{
	struct sb *sb = tux_sb(inode->i_sb);
	struct tux3_inode *tuxnode = tux_inode(inode);
	unsigned delta;

	/* inode has dead mark already */
	if (tux3_inode_is_dead(tuxnode))
		return;

	change_begin_atomic(sb);

	delta = tux3_inode_delta(inode);
	__tux3_mark_inode_to_delete(inode, delta);

	/*
	 * Hack: this is called under inode->i_lock. So, we have to
	 * release inode->i_lock to call mark_inode_dirty_sync().
	 *
	 * FIXME: we want to set I_DIRTY_SYNC (I_DIRTY_SYNC will
	 * prevent the indo is freed) and wakeup flusher if need,
	 * while preventing inode is freed. Need better way to do.
	 */
	if (!(tux3_dirty_flags(inode, delta) & I_DIRTY_SYNC)) {
		/* FIXME: I_REFERENCED can't prevent completely */
		//inode->i_state |= I_REFERENCED;
		/* FIXME: I_WILL_FREE will bother igrab() grabs reference */
		inode->i_state |= I_WILL_FREE;
		spin_unlock(&inode->i_lock);

		/* Tell dead inode to backend by marking as dirty. */
		tux3_mark_inode_dirty_sync(inode);

		spin_lock(&inode->i_lock);
		inode->i_state &= ~I_WILL_FREE;
#ifdef __KERNEL__
		wake_up_bit(&inode->i_state, __I_NEW);
#endif
	}

	change_end_atomic(sb);
}
Beispiel #9
0
static void tux3_put_super(struct super_block *sb)
{
	struct sb *sbi = tux_sb(sb);

	/* FIXME: remove this, then use sb->s_dirt instead */
	tux3_write_super(sb);

	destroy_defer_bfree(&sbi->new_decycle);
	destroy_defer_bfree(&sbi->decycle);
	destroy_defer_bfree(&sbi->derollup);
	destroy_defer_bfree(&sbi->defree);
	iput(sbi->atable);
	iput(sbi->bitmap);
	iput(sbi->volmap);
	iput(sbi->logmap);

	BUG_ON(!list_empty(&sbi->alloc_inodes));
	sb->s_fs_info = NULL;
	kfree(sbi);
}
Beispiel #10
0
static int tux3_statfs(struct dentry *dentry, struct kstatfs *buf)
{
	struct super_block *sb = dentry->d_sb;
	struct sb *sbi = tux_sb(sb);

	buf->f_type = sb->s_magic;
	buf->f_bsize = sbi->blocksize;
	buf->f_blocks = sbi->volblocks;
	buf->f_bfree = sbi->freeblocks;
	buf->f_bavail = sbi->freeblocks;
#if 0
	buf->f_files = buf->f_blocks << (sbi->clus_bits - EXFAT_CHUNK_BITS) / 3;
	buf->f_ffree = buf->f_blocks << (sbi->clus_bits - EXFAT_CHUNK_BITS) / 3;
	buf->f_fsid.val[0] = sbi->serial_number;
	/*buf->f_fsid.val[1];*/
#endif
	buf->f_namelen = TUX_NAME_LEN;
//	buf->f_frsize = sbi->blocksize;

	return 0;
}
Beispiel #11
0
static int __tux3_symlink(struct inode *dir, struct dentry *dentry,
			  struct tux_iattr *iattr, const char *symname)
{
	struct sb *sb = tux_sb(dir->i_sb);
	struct inode *inode;
	unsigned len = strlen(symname) + 1;
	int err, err2;

	/* FIXME: We want more length? */
	if (len > PAGE_CACHE_SIZE)
		return -ENAMETOOLONG;

	change_begin(sb);
	inode = tux_new_inode(dir, iattr, 0);
	err = PTR_ERR(inode);
	if (!IS_ERR(inode)) {
		err = tux_create_dirent(dir, &dentry->d_name, inode);
		if (!err) {
			/* FIXME: we may want to initialize symlink earlier */
			err = page_symlink(inode, symname, len);
			if (!err) {
				d_instantiate(dentry, inode);
				unlock_new_inode(inode);
				goto out;
			}

			err2 = tux_del_dirent(dir, dentry);
			if (err2)
				tux3_fs_error(sb, "Failed to recover dir entry (err %d)", err2);
			clear_nlink(inode);
			tux3_mark_inode_dirty(inode);
			unlock_new_inode(inode);
			iput(inode);
		}
	}
out:
	change_end(sb);

	return err;
}
Beispiel #12
0
Datei: dir.c Projekt: Zkin/tux3
int tux_dir_is_empty(struct inode *dir)
{
	struct sb *sb = tux_sb(dir->i_sb);
	block_t block, blocks = dir->i_size >> sb->blockbits;
	__be64 self = cpu_to_be64(tux_inode(dir)->inum);
	struct buffer_head *buffer;

	for (block = 0; block < blocks; block++) {
		buffer = blockread(mapping(dir), block);
		if (!buffer)
			return -EIO;

		tux_dirent *entry = bufdata(buffer);
		tux_dirent *limit = bufdata(buffer) + sb->blocksize - TUX_REC_LEN(1);
		for (; entry <= limit; entry = next_entry(entry)) {
			if (!entry->rec_len) {
				blockput(buffer);
				tux_zero_len_error(dir, block);
				return -EIO;
			}
			if (is_deleted(entry))
				continue;
			if (entry->name[0] != '.')
				goto not_empty;
			if (entry->name_len > 2)
				goto not_empty;
			if (entry->name_len < 2) {
				if (entry->inum != self)
					goto not_empty;
			} else if (entry->name[1] != '.')
				goto not_empty;
		}
		blockput(buffer);
	}
	return 0;
not_empty:
	blockput(buffer);
	return -ENOTEMPTY;
}
Beispiel #13
0
Datei: namei.c Projekt: Zkin/tux3
static struct dentry *tux3_lookup(struct inode *dir, struct dentry *dentry,
				  unsigned int flags)
{
	struct buffer_head *buffer;
	struct inode *inode;
	tux_dirent *entry;
	inum_t inum;

	entry = tux_find_dirent(dir, &dentry->d_name, &buffer);
	if (IS_ERR(entry)) {
		if (PTR_ERR(entry) != -ENOENT)
			return ERR_CAST(entry);
		inode = NULL;
		goto out;
	}
	inum = be64_to_cpu(entry->inum);
	blockput(buffer);

	inode = tux3_iget(tux_sb(dir->i_sb), inum);
out:
	return d_splice_alias(inode, dentry);
}
Beispiel #14
0
/* Find atom of name */
static int find_atom(struct inode *atable, const char *name, unsigned len,
		     atom_t *atom)
{
	if(DEBUG_MODE_K==1)
	{
		printf("\t\t\t\t%25s[K]  %25s  %4d  #in\n",__FILE__,__func__,__LINE__);
	}
	struct sb *sb = tux_sb(atable->i_sb);
	struct buffer_head *buffer;
	tux_dirent *entry;

	entry = tux_find_entry(atable, name, len, &buffer, sb->atomdictsize);
	if (IS_ERR(entry)) {
		int err = PTR_ERR(entry);
		if (err == -ENOENT)
			return -ENODATA;
		return err;
	}

	*atom = entry_atom(entry);
	blockput(buffer);
	return 0;
}
Beispiel #15
0
/* Find free atom */
static int get_freeatom(struct inode *atable, atom_t *atom)
{
	struct sb *sb = tux_sb(atable->i_sb);
	atom_t freeatom = sb->freeatom;

	if (!freeatom) {
		*atom = sb->atomgen++;
		return 0;
	}

	loff_t next = unatom_dict_read(atable, freeatom);
	if (next < 0)
		return next;
	if (!is_free_unatom(next)) {
		tux3_fs_error(sb, "something horrible happened");
		return -EIO;
	}

	*atom = freeatom;
	sb->freeatom = next & ~UNATOM_FREE_MASK;

	return 0;
}
Beispiel #16
0
static int __tux3_symlink(struct inode *dir, struct dentry *dentry,
			  struct tux_iattr *iattr, const char *symname)
{
	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;
	unsigned len = strlen(symname) + 1;
	int err;

	/* FIXME: We want more length? */
	if (len > PAGE_CACHE_SIZE)
		return -ENAMETOOLONG;

	change_begin(sb);
	inode = tux_create_inode(dir, iattr, 0);
	err = PTR_ERR(inode);
	if (!IS_ERR(inode)) {
		err = page_symlink(inode, symname, len);
		if (!err) {
			err = tux_add_dirent(dir, dentry, inode);
			if (!err) {
				unlock_new_inode(inode);
				goto out;
			}
		}
		inode_dec_link_count(inode);
		unlock_new_inode(inode);
		iput(inode);
	}
out:
	change_end(sb);

	return err;
}
Beispiel #17
0
/* Make atom for name */
static int make_atom(struct inode *atable, const char *name, unsigned len,
		     atom_t *atom)
{
	if(DEBUG_MODE_K==1)
	{
		printf("\t\t\t\t%25s[K]  %25s  %4d  #in\n",__FILE__,__func__,__LINE__);
	}
	struct sb *sb = tux_sb(atable->i_sb);
	int err;

	err = find_atom(atable, name, len, atom);
	if (!err)
		return 0;
	if (err != -ENODATA)
		return err;

	err = get_freeatom(atable, atom);
	if (err)
		return err;

	loff_t where = tux_create_entry(atable, name, len, *atom, 0,
					&sb->atomdictsize);
	if (where < 0) {
		/* FIXME: better set a flag that unatom broke or something!!! */
		return where;
	}

	/* Enter into reverse map - maybe verify zero refs? */
	where = unatom_dict_write(atable, *atom, where);
	if (where < 0) {
		/* FIXME: better set a flag that unatom broke or something!!! */
		return where;
	}

	return 0;
}
Beispiel #18
0
static int tux3_link(struct dentry *old_dentry, struct inode *dir,
		     struct dentry *dentry)
{
	struct inode *inode = old_dentry->d_inode;
	struct sb *sb = tux_sb(inode->i_sb);
	int err;

	if (inode->i_nlink >= TUX_LINK_MAX)
		return -EMLINK;

	change_begin(sb);
	tux3_iattrdirty(inode);
	inode->i_ctime = gettime();
	inode_inc_link_count(inode);
	ihold(inode);
	err = tux_add_dirent(dir, dentry, inode);
	if (err) {
		inode_dec_link_count(inode);
		iput(inode);
	}
	change_end(sb);

	return err;
}
Beispiel #19
0
/* Make atom for name */
static int make_atom(struct inode *atable, const char *name, unsigned len,
		     atom_t *atom)
{
	struct sb *sb = tux_sb(atable->i_sb);
	struct buffer_head *buffer;
	loff_t where;
	int err;

	err = find_atom(atable, name, len, atom);
	if (!err)
		return 0;
	if (err != -ENODATA)
		return err;

	err = get_freeatom(atable, atom);
	if (err)
		return err;

	where = tux_alloc_entry(atable, name, len, &sb->atomdictsize, &buffer);
	if (where < 0) {
		/* FIXME: better set a flag that unatom broke or something!!! */
		return where;
	}
	/* This releases buffer */
	tux_set_entry(buffer, bufdata(buffer) + (where & sb->blockmask),
		      *atom, 0);

	/* Enter into reverse map - maybe verify zero refs? */
	where = unatom_dict_write(atable, *atom, where);
	if (where < 0) {
		/* FIXME: better set a flag that unatom broke or something!!! */
		return where;
	}

	return 0;
}
Beispiel #20
0
static int tux3_fill_super(struct super_block *sb, void *data, int silent)
{
	struct sb *sbi;
	int err, blocksize;

	sbi = kzalloc(sizeof(struct sb), GFP_KERNEL);
	if (!sbi)
		return -ENOMEM;
	sbi->vfs_sb = sb;
	sb->s_fs_info = sbi;
	sb->s_maxbytes = MAX_LFS_FILESIZE;
	sb->s_magic = TUX3_SUPER_MAGIC;
	sb->s_op = &tux3_super_ops;
	sb->s_time_gran = 1;

	mutex_init(&sbi->loglock);
	INIT_LIST_HEAD(&sbi->alloc_inodes);

	err = -EIO;
	blocksize = sb_min_blocksize(sb, BLOCK_SIZE);
	if (!blocksize) {
		if (!silent)
			printk(KERN_ERR "TUX3: unable to set blocksize\n");
		goto error;
	}

	if ((err = load_sb(tux_sb(sb)))) {
		if (!silent) {
			if (err == -EINVAL)
				warn("invalid superblock [%Lx]",
					(L)from_be_u64(*(be_u64 *)sbi->super.magic));
			else
				warn("Unable to read superblock");
		}
		goto error;
	}

	if (sbi->blocksize != blocksize) {
		if (!sb_set_blocksize(sb, sbi->blocksize)) {
			printk(KERN_ERR "TUX3: blocksize too small for device.\n");
			goto error;
		}
	}
	warn("s_blocksize %lu", sb->s_blocksize);

	err = -ENOMEM;
	sbi->volmap = tux_new_volmap(tux_sb(sb));
	if (!sbi->volmap)
		goto error;
	insert_inode_hash(sbi->volmap);

	sbi->logmap = tux_new_logmap(tux_sb(sb));
	if (!sbi->logmap)
		goto error_logmap;

	err = load_itable(sbi);
	if (err)
		goto error_bitmap;

//	struct inode *vtable;
	sbi->bitmap = tux3_iget(sb, TUX_BITMAP_INO);
	err = PTR_ERR(sbi->bitmap);
	if (IS_ERR(sbi->bitmap))
		goto error_bitmap;

	sbi->rootdir = tux3_iget(sb, TUX_ROOTDIR_INO);
	err = PTR_ERR(sbi->rootdir);
	if (IS_ERR(sbi->rootdir))
		goto error_rootdir;

	sbi->atable = tux3_iget(sb, TUX_ATABLE_INO);
	err = PTR_ERR(sbi->atable);
	if (IS_ERR(sbi->atable))
		goto error_atable;

	sb->s_root = d_alloc_root(sbi->rootdir);
	if (!sb->s_root)
		goto error_alloc_root;

	return 0;

error_alloc_root:
	iput(sbi->atable);
error_atable:
	iput(sbi->rootdir);
error_rootdir:
	iput(sbi->bitmap);
error_bitmap:
	iput(sbi->logmap);
error_logmap:
	iput(sbi->volmap);
error:
	kfree(sbi);
	return err;
}
Beispiel #21
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;
}
Beispiel #22
0
static int tux3_fill_super(struct super_block *sb, void *data, int silent)
{
	static struct tux_iattr iattr;
	struct sb *sbi;
	struct root iroot;
	int err, blocksize;

	sbi = kzalloc(sizeof(struct sb), GFP_KERNEL);
	if (!sbi)
		return -ENOMEM;
	sbi->vfs_sb = sb;
	sb->s_fs_info = sbi;
	sb->s_maxbytes = MAX_LFS_FILESIZE;
	sb->s_magic = 0x54555833;
	sb->s_op = &tux3_super_ops;
	sb->s_time_gran = 1;

	mutex_init(&sbi->loglock);

	err = -EIO;
	blocksize = sb_min_blocksize(sb, BLOCK_SIZE);
	if (!blocksize) {
		if (!silent)
			printk(KERN_ERR "TUX3: unable to set blocksize\n");
		goto error;
	}

	err = tux_load_sb(sb, &iroot, silent);
	if (err)
		goto error;
	printk("%s: depth %Lu, block %Lu\n",
	       __func__, (L)iroot.depth, (L)iroot.block);
	printk("%s: blocksize %u, blockbits %u, blockmask %08x\n",
	       __func__, sbi->blocksize, sbi->blockbits, sbi->blockmask);
	printk("%s: volblocks %Lu, freeblocks %Lu, nextalloc %Lu\n",
	       __func__, sbi->volblocks, sbi->freeblocks, sbi->nextalloc);
	printk("%s: freeatom %u, atomgen %u\n",
	       __func__, sbi->freeatom, sbi->atomgen);

	if (sbi->blocksize != blocksize) {
		if (!sb_set_blocksize(sb, sbi->blocksize)) {
			printk(KERN_ERR "TUX3: blocksize too small for device.\n");
			goto error;
		}
	}
	printk("%s: s_blocksize %lu\n", __func__, sb->s_blocksize);

	err = -ENOMEM;
	sbi->volmap = tux_new_volmap(tux_sb(sb));
	if (!sbi->volmap)
		goto error;

	/* Initialize itable btree */
	init_btree(itable_btree(sbi), sbi, iroot, &itable_ops);

//	struct inode *vtable;
	sbi->bitmap = tux3_iget(sb, TUX_BITMAP_INO);
	err = PTR_ERR(sbi->bitmap);
	if (IS_ERR(sbi->bitmap))
		goto error_bitmap;

	sbi->rootdir = tux3_iget(sb, TUX_ROOTDIR_INO);
	err = PTR_ERR(sbi->rootdir);
	if (IS_ERR(sbi->rootdir))
		goto error_rootdir;

	sbi->atable = tux3_iget(sb, TUX_ATABLE_INO);
	err = PTR_ERR(sbi->atable);
	if (IS_ERR(sbi->atable))
		goto error_atable;

	err = -ENOMEM;
	sbi->logmap = tux_new_inode(sbi->rootdir, &iattr, 0);
	if (!sbi->logmap)
		goto error_logmap;

	sb->s_root = d_alloc_root(sbi->rootdir);
	if (!sb->s_root)
		goto error_alloc_root;

	return 0;

error_alloc_root:
	iput(sbi->logmap);
error_logmap:
	iput(sbi->atable);
error_atable:
	iput(sbi->rootdir);
error_rootdir:
	iput(sbi->bitmap);
error_bitmap:
	iput(sbi->volmap);
error:
	kfree(sbi);
	return err;
}
Beispiel #23
0
static int tux3_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
{
	struct inode *inode = file_inode(vma->vm_file);
	struct sb *sb = tux_sb(inode->i_sb);
	struct page *clone, *page = vmf->page;
	void *ptr;
	int ret;

	sb_start_pagefault(inode->i_sb);

retry:
	down_read(&tux_inode(inode)->truncate_lock);
	lock_page(page);
	if (page->mapping != mapping(inode)) {
		unlock_page(page);
		ret = VM_FAULT_NOPAGE;
		goto out;
	}

	/*
	 * page fault can be happened while holding change_begin/end()
	 * (e.g. copy of user data between ->write_begin and
	 * ->write_end for write(2)).
	 *
	 * So, we use nested version here.
	 */
	change_begin_atomic_nested(sb, &ptr);

	/*
	 * FIXME: Caller releases vmf->page (old_page) unconditionally.
	 * So, this takes additional refcount to workaround it.
	 */
	if (vmf->page == page)
		page_cache_get(page);

	clone = pagefork_for_blockdirty(page, tux3_get_current_delta());
	if (IS_ERR(clone)) {
		/* Someone did page fork */
		pgoff_t index = page->index;

		change_end_atomic_nested(sb, ptr);
		unlock_page(page);
		page_cache_release(page);
		up_read(&tux_inode(inode)->truncate_lock);

		switch (PTR_ERR(clone)) {
		case -EAGAIN:
			page = find_get_page(inode->i_mapping, index);
			assert(page);
			goto retry;
		case -ENOMEM:
			ret = VM_FAULT_OOM;
			break;
		default:
			ret = VM_FAULT_SIGBUS;
			break;
		}

		goto out;
	}

	file_update_time(vma->vm_file);

	/* Assign buffers to dirty */
	if (!page_has_buffers(clone))
		create_empty_buffers(clone, sb->blocksize, 0);

	/*
	 * We mark the page dirty already here so that when freeze is in
	 * progress, we are guaranteed that writeback during freezing will
	 * see the dirty page and writeprotect it again.
	 */
	tux3_set_page_dirty(clone);
#if 1
	/* FIXME: Caller doesn't see the changed vmf->page */
	vmf->page = clone;

	change_end_atomic_nested(sb, ptr);
	/* FIXME: caller doesn't know about pagefork */
	unlock_page(clone);
	page_cache_release(clone);
	ret = 0;
//	ret = VM_FAULT_LOCKED;
#endif
out:
	up_read(&tux_inode(inode)->truncate_lock);
	sb_end_pagefault(inode->i_sb);

	return ret;
}
Beispiel #24
0
static int tux3_symlink(struct inode *dir, struct dentry *dentry,
			const char *symname)
{
	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 tux3_unlink(struct inode *dir, struct dentry *dentry)
{
	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)
{
	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)
{
	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_create_dirent(new_dir, &new_dentry->d_name,
					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,
};
Beispiel #25
0
int main(int argc, char *argv[])
{
	unsigned abits = DATA_BTREE_BIT|CTIME_SIZE_BIT|MODE_OWNER_BIT|LINK_COUNT_BIT|MTIME_BIT;
	struct dev *dev = &(struct dev){ .bits = 8, .fd = open(argv[1], O_CREAT|O_RDWR, S_IRUSR|S_IWUSR) };
	assert(!ftruncate(dev->fd, 1 << 24));
	init_buffers(dev, 1 << 20, 0);
	struct sb *sb = rapid_sb(dev,
		.version = 0,
		.atomref_base = 1 << 10,
		.unatom_base = 1 << 11,
		.atomgen = 1);
	struct inode *inode = rapid_open_inode(sb, NULL, S_IFDIR | 0x666,
		.present = abits, .i_uid = 0x12121212, .i_gid = 0x34343434,
		.i_ctime = spectime(0xdec0debeadULL),
		.i_mtime = spectime(0xbadfaced00dULL));
	inode->btree = (struct btree){
		.root = { .block = 0xcaba1f00dULL, .depth = 3 }
	};
	sb->atable = inode;

	for (int i = 0; i < 2; i++) {
		struct buffer_head *buffer = blockget(mapping(inode), tux_sb(inode->i_sb)->atomref_base + i);
		memset(bufdata(buffer), 0, sb->blocksize);
		blockput_dirty(buffer);
	}

	if (1) {
		warn("---- test positive and negative refcount carry ----");
		use_atom(inode, 6, 1 << 15);
		use_atom(inode, 6, (1 << 15));
		use_atom(inode, 6, -(1 << 15));
		use_atom(inode, 6, -(1 << 15));
	}

	warn("---- test atom table ----");
	printf("atom = %Lx\n", (L)make_atom(inode, "foo", 3));
	printf("atom = %Lx\n", (L)make_atom(inode, "foo", 3));
	printf("atom = %Lx\n", (L)make_atom(inode, "bar", 3));
	printf("atom = %Lx\n", (L)make_atom(inode, "foo", 3));
	printf("atom = %Lx\n", (L)make_atom(inode, "bar", 3));

	warn("---- test inode xattr cache ----");
	int err;
	err = xcache_update(inode, 0x666, "hello", 5, 0);
	if (err)
		printf("err %d\n", err);
	err = xcache_update(inode, 0x777, "world!", 6, 0);
	if (err)
		printf("err %d\n", err);
	xcache_dump(inode);
	struct xattr *xattr = xcache_lookup(tux_inode(inode)->xcache, 0x777);
	if (!IS_ERR(xattr))
		printf("atom %x => %.*s\n", xattr->atom, xattr->size, xattr->body);
	err = xcache_update(inode, 0x111, "class", 5, 0);
	if (err)
		printf("err %d\n", err);
	err = xcache_update(inode, 0x666, NULL, 0, 0);
	if (err)
		printf("err %d\n", err);
	err = xcache_update(inode, 0x222, "boooyah", 7, 0);
	if (err)
		printf("err %d\n", err);
	xcache_dump(inode);

	warn("---- test xattr inode table encode and decode ----");
	char attrs[1000] = { };
	char *top = encode_xattrs(inode, attrs, sizeof(attrs));
	hexdump(attrs, top - attrs);
	printf("predicted size = %x, encoded size = %Lx\n", encode_xsize(inode), (L)(top - attrs));
	inode->xcache->size = offsetof(struct xcache, xattrs);
	char *newtop = decode_attrs(inode, attrs, top - attrs);
	printf("predicted size = %x, xcache size = %x\n", decode_xsize(inode, attrs, top - attrs), inode->xcache->size);
	assert(top == newtop);
	xcache_dump(inode);
	free(inode->xcache);
	inode->xcache = NULL;
	warn("---- xattr update ----");
	set_xattr(inode, "hello", 5, "world!", 6, 0);
	set_xattr(inode, "empty", 5, "zot", 0, 0);
	set_xattr(inode, "foo", 3, "foobar", 6, 0);
	xcache_dump(inode);
	warn("---- xattr remove ----");
//	del_xattr(inode, "hello", 5);
	xcache_dump(inode);
	warn("---- xattr lookup ----");
	for (int i = 0, len; i < 3; i++) {
		char *namelist[] = { "hello", "foo", "world" }, *name = namelist[i];
		char data[100];
		int size = get_xattr(inode, name, len = strlen(name), data, sizeof(data));
		if (size < 0)
			printf("xattr %.*s not found (%s)\n", len, name, strerror(-size));
		else
			printf("found xattr %.*s => %.*s\n", len, name, size, data);
	}
	warn("---- list xattrs ----");
	int len = xattr_list(inode, attrs, sizeof(attrs));
	printf("xattr list length = %i\n", xattr_list(inode, NULL, 0));
	hexdump(attrs, len);

	warn("---- atom reverse map ----");
	for (int i = 0; i < 5; i++) {
		unsigned atom = i, offset;
		struct buffer_head *buffer = blockread_unatom(inode, atom, &offset);
		loff_t where = from_be_u64(((be_u64 *)bufdata(buffer))[offset]);
		blockput_dirty(buffer);
		buffer = blockread(mapping(inode), where >> sb->blockbits);
		printf("atom %.3Lx at dirent %.4Lx, ", (L)atom, (L)where);
		hexdump(bufdata(buffer) + (where & sb->blockmask), 16);
		blockput(buffer);
	}
	warn("---- atom recycle ----");
	set_xattr(inode, "hello", 5, NULL, 0, 0);
	show_freeatoms(sb);
	printf("got free atom %x\n", get_freeatom(inode));
	printf("got free atom %x\n", get_freeatom(inode));
	printf("got free atom %x\n", get_freeatom(inode));

	warn("---- dump atom table ----");
	dump_atoms(inode);
	show_buffers(inode->map);
	exit(0);
}
Beispiel #26
0
Datei: dir.c Projekt: Zkin/tux3
loff_t tux_create_entry(struct inode *dir, const char *name, unsigned len,
			inum_t inum, umode_t mode, loff_t *size)
{
	unsigned delta = tux3_get_current_delta();
	struct sb *sb = tux_sb(dir->i_sb);
	tux_dirent *entry;
	struct buffer_head *buffer, *clone;
	unsigned reclen = TUX_REC_LEN(len), rec_len, name_len, offset;
	unsigned blocksize = sb->blocksize;
	block_t block, blocks = *size >> sb->blockbits;
	void *olddata;

	for (block = 0; block < blocks; block++) {
		buffer = blockread(mapping(dir), block);
		if (!buffer)
			return -EIO;
		entry = bufdata(buffer);
		tux_dirent *limit = bufdata(buffer) + blocksize - reclen;
		while (entry <= limit) {
			if (entry->rec_len == 0) {
				blockput(buffer);
				tux_zero_len_error(dir, block);
				return -EIO;
			}
			name_len = TUX_REC_LEN(entry->name_len);
			rec_len = tux_rec_len_from_disk(entry->rec_len);
			if (is_deleted(entry) && rec_len >= reclen)
				goto create;
			if (rec_len >= name_len + reclen)
				goto create;
			entry = (void *)entry + rec_len;
		}
		blockput(buffer);
	}
	entry = NULL;
	buffer = blockget(mapping(dir), block);
	assert(!buffer_dirty(buffer));

create:
	/*
	 * The directory is protected by i_mutex.
	 * blockdirty() should never return -EAGAIN.
	 */
	olddata = bufdata(buffer);
	clone = blockdirty(buffer, delta);
	if (IS_ERR(clone)) {
		assert(PTR_ERR(clone) != -EAGAIN);
		blockput(buffer);
		return PTR_ERR(clone);
	}
	if (!entry) {
		/* Expanding the directory size. Initialize block. */
		entry = bufdata(clone);
		memset(entry, 0, blocksize);
		entry->rec_len = tux_rec_len_to_disk(blocksize);
		assert(is_deleted(entry));

		*size += blocksize;
	} else {
		entry = ptr_redirect(entry, olddata, bufdata(clone));

		if (!is_deleted(entry)) {
			tux_dirent *newent = (void *)entry + name_len;
			unsigned rest_rec_len = rec_len - name_len;
			newent->rec_len = tux_rec_len_to_disk(rest_rec_len);
			entry->rec_len = tux_rec_len_to_disk(name_len);
			entry = newent;
		}
	}

	entry->name_len = len;
	memcpy(entry->name, name, len);
	offset = (void *)entry - bufdata(clone);
	/* this releases buffer */
	tux_update_entry(clone, entry, inum, mode);

	return (block << sb->blockbits) + offset; /* only for xattr create */
}
/*
 * Almost copy of generic_file_splice_write() (added changed_begin/end,
 * tux3_iattrdirty()).
 */
static ssize_t tux3_file_splice_write(struct pipe_inode_info *pipe,
				      struct file *out, loff_t *ppos,
				      size_t len, unsigned int flags)
{
	if(DEBUG_MODE_K==1)
	{
		printk(KERN_INFO"%25s  %25s  %4d  #in\n",__FILE__,__func__,__LINE__);
	}
	struct address_space *mapping = out->f_mapping;
	struct inode *inode = mapping->host;
	struct sb *sb = tux_sb(inode->i_sb);
	struct splice_desc sd = {
		.total_len = len,
		.flags = flags,
		.pos = *ppos,
		.u.file = out,
	};
	ssize_t ret;

	sb_start_write(inode->i_sb);

	pipe_lock(pipe);

	splice_from_pipe_begin(&sd);
	do {
		ret = splice_from_pipe_next(pipe, &sd);
		if (ret <= 0)
			break;

		mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
		/* For each ->write_end() calls change_end(). */
		change_begin(sb);
		/* For timestamp. FIXME: convert this to ->update_time
		 * handler? */
		tux3_iattrdirty(inode);
		ret = file_remove_suid(out);
		if (!ret) {
			ret = file_update_time(out);
			if (!ret)
				ret = splice_from_pipe_feed(pipe, &sd,
							    pipe_to_file);
		}
		change_end_if_needed(sb);
		mutex_unlock(&inode->i_mutex);
	} while (ret > 0);
	splice_from_pipe_end(pipe, &sd);

	pipe_unlock(pipe);

	if (sd.num_spliced)
		ret = sd.num_spliced;

	if (ret > 0) {
		int err;

		err = generic_write_sync(out, *ppos, ret);
		if (err)
			ret = err;
		else
			*ppos += ret;
		balance_dirty_pages_ratelimited(mapping);
	}
	sb_end_write(inode->i_sb);

	return ret;
}