Commit 397aa6b6 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull minix updates from Al Viro:
 "Assorted fixes - mostly Christoph's"

* 'work.minix' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  minix_rename(): minix_delete_entry() might fail
  minix: don't flush page immediately for DIRSYNC directories
  minix: fix error handling in minix_set_link
  minix: fix error handling in minix_delete_entry
  minix: move releasing pages into unlink and rename
  minix: make minix_new_inode() return error as ERR_PTR(-E...)
parents 595fa4e3 2cb6a442
Loading
Loading
Loading
Loading
+6 −10
Original line number Diff line number Diff line
@@ -210,7 +210,7 @@ void minix_free_inode(struct inode * inode)
	mark_buffer_dirty(bh);
}

struct inode *minix_new_inode(const struct inode *dir, umode_t mode, int *error)
struct inode *minix_new_inode(const struct inode *dir, umode_t mode)
{
	struct super_block *sb = dir->i_sb;
	struct minix_sb_info *sbi = minix_sb(sb);
@@ -220,13 +220,10 @@ struct inode *minix_new_inode(const struct inode *dir, umode_t mode, int *error)
	unsigned long j;
	int i;

	if (!inode) {
		*error = -ENOMEM;
		return NULL;
	}
	if (!inode)
		return ERR_PTR(-ENOMEM);
	j = bits_per_zone;
	bh = NULL;
	*error = -ENOSPC;
	spin_lock(&bitmap_lock);
	for (i = 0; i < sbi->s_imap_blocks; i++) {
		bh = sbi->s_imap[i];
@@ -237,20 +234,20 @@ struct inode *minix_new_inode(const struct inode *dir, umode_t mode, int *error)
	if (!bh || j >= bits_per_zone) {
		spin_unlock(&bitmap_lock);
		iput(inode);
		return NULL;
		return ERR_PTR(-ENOSPC);
	}
	if (minix_test_and_set_bit(j, bh->b_data)) {	/* shouldn't happen */
		spin_unlock(&bitmap_lock);
		printk("minix_new_inode: bit already set\n");
		iput(inode);
		return NULL;
		return ERR_PTR(-ENOSPC);
	}
	spin_unlock(&bitmap_lock);
	mark_buffer_dirty(bh);
	j += i * bits_per_zone;
	if (!j || j > sbi->s_ninodes) {
		iput(inode);
		return NULL;
		return ERR_PTR(-ENOSPC);
	}
	inode_init_owner(&nop_mnt_idmap, inode, dir, mode);
	inode->i_ino = j;
@@ -260,7 +257,6 @@ struct inode *minix_new_inode(const struct inode *dir, umode_t mode, int *error)
	insert_inode_hash(inode);
	mark_inode_dirty(inode);

	*error = 0;
	return inode;
}

+34 −28
Original line number Diff line number Diff line
@@ -46,21 +46,27 @@ minix_last_byte(struct inode *inode, unsigned long page_nr)
	return last_byte;
}

static int dir_commit_chunk(struct page *page, loff_t pos, unsigned len)
static void dir_commit_chunk(struct page *page, loff_t pos, unsigned len)
{
	struct address_space *mapping = page->mapping;
	struct inode *dir = mapping->host;
	int err = 0;

	block_write_end(NULL, mapping, pos, len, len, page, NULL);

	if (pos+len > dir->i_size) {
		i_size_write(dir, pos+len);
		mark_inode_dirty(dir);
	}
	if (IS_DIRSYNC(dir))
		err = write_one_page(page);
	else
	unlock_page(page);
}

static int minix_handle_dirsync(struct inode *dir)
{
	int err;

	err = filemap_write_and_wait(dir->i_mapping);
	if (!err)
		err = sync_inode_metadata(dir, 1);
	return err;
}

@@ -274,9 +280,10 @@ int minix_add_link(struct dentry *dentry, struct inode *inode)
		memset (namx + namelen, 0, sbi->s_dirsize - namelen - 2);
		de->inode = inode->i_ino;
	}
	err = dir_commit_chunk(page, pos, sbi->s_dirsize);
	dir_commit_chunk(page, pos, sbi->s_dirsize);
	dir->i_mtime = dir->i_ctime = current_time(dir);
	mark_inode_dirty(dir);
	err = minix_handle_dirsync(dir);
out_put:
	dir_put_page(page);
out:
@@ -297,19 +304,18 @@ int minix_delete_entry(struct minix_dir_entry *de, struct page *page)

	lock_page(page);
	err = minix_prepare_chunk(page, pos, len);
	if (err == 0) {
	if (err) {
		unlock_page(page);
		return err;
	}
	if (sbi->s_version == MINIX_V3)
		((minix3_dirent *)de)->inode = 0;
	else
		de->inode = 0;
		err = dir_commit_chunk(page, pos, len);
	} else {
		unlock_page(page);
	}
	dir_put_page(page);
	dir_commit_chunk(page, pos, len);
	inode->i_ctime = inode->i_mtime = current_time(inode);
	mark_inode_dirty(inode);
	return err;
	return minix_handle_dirsync(inode);
}

int minix_make_empty(struct inode *inode, struct inode *dir)
@@ -349,7 +355,8 @@ int minix_make_empty(struct inode *inode, struct inode *dir)
	}
	kunmap_atomic(kaddr);

	err = dir_commit_chunk(page, 0, 2 * sbi->s_dirsize);
	dir_commit_chunk(page, 0, 2 * sbi->s_dirsize);
	err = minix_handle_dirsync(inode);
fail:
	put_page(page);
	return err;
@@ -409,7 +416,7 @@ int minix_empty_dir(struct inode * inode)
}

/* Releases the page */
void minix_set_link(struct minix_dir_entry *de, struct page *page,
int minix_set_link(struct minix_dir_entry *de, struct page *page,
		struct inode *inode)
{
	struct inode *dir = page->mapping->host;
@@ -419,20 +426,19 @@ void minix_set_link(struct minix_dir_entry *de, struct page *page,
	int err;

	lock_page(page);

	err = minix_prepare_chunk(page, pos, sbi->s_dirsize);
	if (err == 0) {
	if (err) {
		unlock_page(page);
		return err;
	}
	if (sbi->s_version == MINIX_V3)
		((minix3_dirent *)de)->inode = inode->i_ino;
	else
		de->inode = inode->i_ino;
		err = dir_commit_chunk(page, pos, sbi->s_dirsize);
	} else {
		unlock_page(page);
	}
	dir_put_page(page);
	dir_commit_chunk(page, pos, sbi->s_dirsize);
	dir->i_mtime = dir->i_ctime = current_time(dir);
	mark_inode_dirty(dir);
	return minix_handle_dirsync(dir);
}

struct minix_dir_entry * minix_dotdot (struct inode *dir, struct page **p)
+3 −2
Original line number Diff line number Diff line
@@ -45,7 +45,7 @@ struct minix_sb_info {
extern struct inode *minix_iget(struct super_block *, unsigned long);
extern struct minix_inode * minix_V1_raw_inode(struct super_block *, ino_t, struct buffer_head **);
extern struct minix2_inode * minix_V2_raw_inode(struct super_block *, ino_t, struct buffer_head **);
extern struct inode * minix_new_inode(const struct inode *, umode_t, int *);
extern struct inode * minix_new_inode(const struct inode *, umode_t);
extern void minix_free_inode(struct inode * inode);
extern unsigned long minix_count_free_inodes(struct super_block *sb);
extern int minix_new_block(struct inode * inode);
@@ -69,7 +69,8 @@ extern int minix_add_link(struct dentry*, struct inode*);
extern int minix_delete_entry(struct minix_dir_entry*, struct page*);
extern int minix_make_empty(struct inode*, struct inode*);
extern int minix_empty_dir(struct inode*);
extern void minix_set_link(struct minix_dir_entry*, struct page*, struct inode*);
int minix_set_link(struct minix_dir_entry *de, struct page *page,
		struct inode *inode);
extern struct minix_dir_entry *minix_dotdot(struct inode*, struct page**);
extern ino_t minix_inode_by_name(struct dentry*);

+48 −52
Original line number Diff line number Diff line
@@ -36,33 +36,31 @@ static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry, un
static int minix_mknod(struct mnt_idmap *idmap, struct inode *dir,
		       struct dentry *dentry, umode_t mode, dev_t rdev)
{
	int error;
	struct inode *inode;

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

	inode = minix_new_inode(dir, mode, &error);
	inode = minix_new_inode(dir, mode);
	if (IS_ERR(inode))
		return PTR_ERR(inode);

	if (inode) {
	minix_set_inode(inode, rdev);
	mark_inode_dirty(inode);
		error = add_nondir(dentry, inode);
	}
	return error;
	return add_nondir(dentry, inode);
}

static int minix_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
			 struct file *file, umode_t mode)
{
	int error;
	struct inode *inode = minix_new_inode(dir, mode, &error);
	if (inode) {
	struct inode *inode = minix_new_inode(dir, mode);

	if (IS_ERR(inode))
		return finish_open_simple(file, PTR_ERR(inode));
	minix_set_inode(inode, 0);
	mark_inode_dirty(inode);
	d_tmpfile(file, inode);
	}
	return finish_open_simple(file, error);
	return finish_open_simple(file, 0);
}

static int minix_create(struct mnt_idmap *idmap, struct inode *dir,
@@ -74,30 +72,25 @@ static int minix_create(struct mnt_idmap *idmap, struct inode *dir,
static int minix_symlink(struct mnt_idmap *idmap, struct inode *dir,
			 struct dentry *dentry, const char *symname)
{
	int err = -ENAMETOOLONG;
	int i = strlen(symname)+1;
	struct inode * inode;
	int err;

	if (i > dir->i_sb->s_blocksize)
		goto out;
		return -ENAMETOOLONG;

	inode = minix_new_inode(dir, S_IFLNK | 0777, &err);
	if (!inode)
		goto out;
	inode = minix_new_inode(dir, S_IFLNK | 0777);
	if (IS_ERR(inode))
		return PTR_ERR(inode);

	minix_set_inode(inode, 0);
	err = page_symlink(inode, symname, i);
	if (err)
		goto out_fail;

	err = add_nondir(dentry, inode);
out:
	return err;

out_fail:
	if (unlikely(err)) {
		inode_dec_link_count(inode);
		iput(inode);
	goto out;
		return err;
	}
	return add_nondir(dentry, inode);
}

static int minix_link(struct dentry * old_dentry, struct inode * dir,
@@ -117,14 +110,12 @@ static int minix_mkdir(struct mnt_idmap *idmap, struct inode *dir,
	struct inode * inode;
	int err;

	inode_inc_link_count(dir);

	inode = minix_new_inode(dir, S_IFDIR | mode, &err);
	if (!inode)
		goto out_dir;
	inode = minix_new_inode(dir, S_IFDIR | mode);
	if (IS_ERR(inode))
		return PTR_ERR(inode);

	inode_inc_link_count(dir);
	minix_set_inode(inode, 0);

	inode_inc_link_count(inode);

	err = minix_make_empty(inode, dir);
@@ -143,30 +134,29 @@ static int minix_mkdir(struct mnt_idmap *idmap, struct inode *dir,
	inode_dec_link_count(inode);
	inode_dec_link_count(inode);
	iput(inode);
out_dir:
	inode_dec_link_count(dir);
	goto out;
}

static int minix_unlink(struct inode * dir, struct dentry *dentry)
{
	int err = -ENOENT;
	struct inode * inode = d_inode(dentry);
	struct page * page;
	struct minix_dir_entry * de;
	int err;

	de = minix_find_entry(dentry, &page);
	if (!de)
		goto end_unlink;

		return -ENOENT;
	err = minix_delete_entry(de, page);
	if (err)
		goto end_unlink;
	kunmap(page);
	put_page(page);

	if (err)
		return err;
	inode->i_ctime = dir->i_ctime;
	inode_dec_link_count(inode);
end_unlink:
	return err;
	return 0;
}

static int minix_rmdir(struct inode * dir, struct dentry *dentry)
@@ -223,7 +213,11 @@ static int minix_rename(struct mnt_idmap *idmap,
		new_de = minix_find_entry(new_dentry, &new_page);
		if (!new_de)
			goto out_dir;
		minix_set_link(new_de, new_page, old_inode);
		err = minix_set_link(new_de, new_page, old_inode);
		kunmap(new_page);
		put_page(new_page);
		if (err)
			goto out_dir;
		new_inode->i_ctime = current_time(new_inode);
		if (dir_de)
			drop_nlink(new_inode);
@@ -236,15 +230,17 @@ static int minix_rename(struct mnt_idmap *idmap,
			inode_inc_link_count(new_dir);
	}

	minix_delete_entry(old_de, old_page);
	err = minix_delete_entry(old_de, old_page);
	if (err)
		goto out_dir;

	mark_inode_dirty(old_inode);

	if (dir_de) {
		minix_set_link(dir_de, dir_page, new_dir);
		err = minix_set_link(dir_de, dir_page, new_dir);
		if (!err)
			inode_dec_link_count(old_dir);
	}
	return 0;

out_dir:
	if (dir_de) {
		kunmap(dir_page);