Commit 397aa6b6 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'work.minix' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

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
...@@ -210,7 +210,7 @@ void minix_free_inode(struct inode * inode) ...@@ -210,7 +210,7 @@ void minix_free_inode(struct inode * inode)
mark_buffer_dirty(bh); 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 super_block *sb = dir->i_sb;
struct minix_sb_info *sbi = minix_sb(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) ...@@ -220,13 +220,10 @@ struct inode *minix_new_inode(const struct inode *dir, umode_t mode, int *error)
unsigned long j; unsigned long j;
int i; int i;
if (!inode) { if (!inode)
*error = -ENOMEM; return ERR_PTR(-ENOMEM);
return NULL;
}
j = bits_per_zone; j = bits_per_zone;
bh = NULL; bh = NULL;
*error = -ENOSPC;
spin_lock(&bitmap_lock); spin_lock(&bitmap_lock);
for (i = 0; i < sbi->s_imap_blocks; i++) { for (i = 0; i < sbi->s_imap_blocks; i++) {
bh = sbi->s_imap[i]; bh = sbi->s_imap[i];
...@@ -237,20 +234,20 @@ struct inode *minix_new_inode(const struct inode *dir, umode_t mode, int *error) ...@@ -237,20 +234,20 @@ struct inode *minix_new_inode(const struct inode *dir, umode_t mode, int *error)
if (!bh || j >= bits_per_zone) { if (!bh || j >= bits_per_zone) {
spin_unlock(&bitmap_lock); spin_unlock(&bitmap_lock);
iput(inode); iput(inode);
return NULL; return ERR_PTR(-ENOSPC);
} }
if (minix_test_and_set_bit(j, bh->b_data)) { /* shouldn't happen */ if (minix_test_and_set_bit(j, bh->b_data)) { /* shouldn't happen */
spin_unlock(&bitmap_lock); spin_unlock(&bitmap_lock);
printk("minix_new_inode: bit already set\n"); printk("minix_new_inode: bit already set\n");
iput(inode); iput(inode);
return NULL; return ERR_PTR(-ENOSPC);
} }
spin_unlock(&bitmap_lock); spin_unlock(&bitmap_lock);
mark_buffer_dirty(bh); mark_buffer_dirty(bh);
j += i * bits_per_zone; j += i * bits_per_zone;
if (!j || j > sbi->s_ninodes) { if (!j || j > sbi->s_ninodes) {
iput(inode); iput(inode);
return NULL; return ERR_PTR(-ENOSPC);
} }
inode_init_owner(&nop_mnt_idmap, inode, dir, mode); inode_init_owner(&nop_mnt_idmap, inode, dir, mode);
inode->i_ino = j; inode->i_ino = j;
...@@ -260,7 +257,6 @@ struct inode *minix_new_inode(const struct inode *dir, umode_t mode, int *error) ...@@ -260,7 +257,6 @@ struct inode *minix_new_inode(const struct inode *dir, umode_t mode, int *error)
insert_inode_hash(inode); insert_inode_hash(inode);
mark_inode_dirty(inode); mark_inode_dirty(inode);
*error = 0;
return inode; return inode;
} }
......
...@@ -46,21 +46,27 @@ minix_last_byte(struct inode *inode, unsigned long page_nr) ...@@ -46,21 +46,27 @@ minix_last_byte(struct inode *inode, unsigned long page_nr)
return last_byte; 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 address_space *mapping = page->mapping;
struct inode *dir = mapping->host; struct inode *dir = mapping->host;
int err = 0;
block_write_end(NULL, mapping, pos, len, len, page, NULL); block_write_end(NULL, mapping, pos, len, len, page, NULL);
if (pos+len > dir->i_size) { if (pos+len > dir->i_size) {
i_size_write(dir, pos+len); i_size_write(dir, pos+len);
mark_inode_dirty(dir); mark_inode_dirty(dir);
} }
if (IS_DIRSYNC(dir))
err = write_one_page(page);
else
unlock_page(page); 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; return err;
} }
...@@ -274,9 +280,10 @@ int minix_add_link(struct dentry *dentry, struct inode *inode) ...@@ -274,9 +280,10 @@ int minix_add_link(struct dentry *dentry, struct inode *inode)
memset (namx + namelen, 0, sbi->s_dirsize - namelen - 2); memset (namx + namelen, 0, sbi->s_dirsize - namelen - 2);
de->inode = inode->i_ino; 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); dir->i_mtime = dir->i_ctime = current_time(dir);
mark_inode_dirty(dir); mark_inode_dirty(dir);
err = minix_handle_dirsync(dir);
out_put: out_put:
dir_put_page(page); dir_put_page(page);
out: out:
...@@ -297,19 +304,18 @@ int minix_delete_entry(struct minix_dir_entry *de, struct page *page) ...@@ -297,19 +304,18 @@ int minix_delete_entry(struct minix_dir_entry *de, struct page *page)
lock_page(page); lock_page(page);
err = minix_prepare_chunk(page, pos, len); err = minix_prepare_chunk(page, pos, len);
if (err == 0) { if (err) {
unlock_page(page);
return err;
}
if (sbi->s_version == MINIX_V3) if (sbi->s_version == MINIX_V3)
((minix3_dirent *) de)->inode = 0; ((minix3_dirent *)de)->inode = 0;
else else
de->inode = 0; de->inode = 0;
err = dir_commit_chunk(page, pos, len); dir_commit_chunk(page, pos, len);
} else {
unlock_page(page);
}
dir_put_page(page);
inode->i_ctime = inode->i_mtime = current_time(inode); inode->i_ctime = inode->i_mtime = current_time(inode);
mark_inode_dirty(inode); mark_inode_dirty(inode);
return err; return minix_handle_dirsync(inode);
} }
int minix_make_empty(struct inode *inode, struct inode *dir) int minix_make_empty(struct inode *inode, struct inode *dir)
...@@ -349,7 +355,8 @@ 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); 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: fail:
put_page(page); put_page(page);
return err; return err;
...@@ -409,7 +416,7 @@ int minix_empty_dir(struct inode * inode) ...@@ -409,7 +416,7 @@ int minix_empty_dir(struct inode * inode)
} }
/* Releases the page */ /* 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 *inode)
{ {
struct inode *dir = page->mapping->host; struct inode *dir = page->mapping->host;
...@@ -419,20 +426,19 @@ void minix_set_link(struct minix_dir_entry *de, struct page *page, ...@@ -419,20 +426,19 @@ void minix_set_link(struct minix_dir_entry *de, struct page *page,
int err; int err;
lock_page(page); lock_page(page);
err = minix_prepare_chunk(page, pos, sbi->s_dirsize); 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) if (sbi->s_version == MINIX_V3)
((minix3_dirent *) de)->inode = inode->i_ino; ((minix3_dirent *)de)->inode = inode->i_ino;
else else
de->inode = inode->i_ino; de->inode = inode->i_ino;
err = dir_commit_chunk(page, pos, sbi->s_dirsize); dir_commit_chunk(page, pos, sbi->s_dirsize);
} else {
unlock_page(page);
}
dir_put_page(page);
dir->i_mtime = dir->i_ctime = current_time(dir); dir->i_mtime = dir->i_ctime = current_time(dir);
mark_inode_dirty(dir); mark_inode_dirty(dir);
return minix_handle_dirsync(dir);
} }
struct minix_dir_entry * minix_dotdot (struct inode *dir, struct page **p) struct minix_dir_entry * minix_dotdot (struct inode *dir, struct page **p)
......
...@@ -45,7 +45,7 @@ struct minix_sb_info { ...@@ -45,7 +45,7 @@ struct minix_sb_info {
extern struct inode *minix_iget(struct super_block *, unsigned long); 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 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 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 void minix_free_inode(struct inode * inode);
extern unsigned long minix_count_free_inodes(struct super_block *sb); extern unsigned long minix_count_free_inodes(struct super_block *sb);
extern int minix_new_block(struct inode * inode); extern int minix_new_block(struct inode * inode);
...@@ -69,7 +69,8 @@ extern int minix_add_link(struct dentry*, struct 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_delete_entry(struct minix_dir_entry*, struct page*);
extern int minix_make_empty(struct inode*, struct inode*); extern int minix_make_empty(struct inode*, struct inode*);
extern int minix_empty_dir(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 struct minix_dir_entry *minix_dotdot(struct inode*, struct page**);
extern ino_t minix_inode_by_name(struct dentry*); extern ino_t minix_inode_by_name(struct dentry*);
......
...@@ -36,33 +36,31 @@ static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry, un ...@@ -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, static int minix_mknod(struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, umode_t mode, dev_t rdev) struct dentry *dentry, umode_t mode, dev_t rdev)
{ {
int error;
struct inode *inode; struct inode *inode;
if (!old_valid_dev(rdev)) if (!old_valid_dev(rdev))
return -EINVAL; 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); minix_set_inode(inode, rdev);
mark_inode_dirty(inode); mark_inode_dirty(inode);
error = add_nondir(dentry, inode); return add_nondir(dentry, inode);
}
return error;
} }
static int minix_tmpfile(struct mnt_idmap *idmap, struct inode *dir, static int minix_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
struct file *file, umode_t mode) struct file *file, umode_t mode)
{ {
int error; struct inode *inode = minix_new_inode(dir, mode);
struct inode *inode = minix_new_inode(dir, mode, &error);
if (inode) { if (IS_ERR(inode))
return finish_open_simple(file, PTR_ERR(inode));
minix_set_inode(inode, 0); minix_set_inode(inode, 0);
mark_inode_dirty(inode); mark_inode_dirty(inode);
d_tmpfile(file, inode); d_tmpfile(file, inode);
} return finish_open_simple(file, 0);
return finish_open_simple(file, error);
} }
static int minix_create(struct mnt_idmap *idmap, struct inode *dir, 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, ...@@ -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, static int minix_symlink(struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, const char *symname) struct dentry *dentry, const char *symname)
{ {
int err = -ENAMETOOLONG;
int i = strlen(symname)+1; int i = strlen(symname)+1;
struct inode * inode; struct inode * inode;
int err;
if (i > dir->i_sb->s_blocksize) if (i > dir->i_sb->s_blocksize)
goto out; return -ENAMETOOLONG;
inode = minix_new_inode(dir, S_IFLNK | 0777, &err); inode = minix_new_inode(dir, S_IFLNK | 0777);
if (!inode) if (IS_ERR(inode))
goto out; return PTR_ERR(inode);
minix_set_inode(inode, 0); minix_set_inode(inode, 0);
err = page_symlink(inode, symname, i); err = page_symlink(inode, symname, i);
if (err) if (unlikely(err)) {
goto out_fail;
err = add_nondir(dentry, inode);
out:
return err;
out_fail:
inode_dec_link_count(inode); inode_dec_link_count(inode);
iput(inode); iput(inode);
goto out; return err;
}
return add_nondir(dentry, inode);
} }
static int minix_link(struct dentry * old_dentry, struct inode * dir, 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, ...@@ -117,14 +110,12 @@ static int minix_mkdir(struct mnt_idmap *idmap, struct inode *dir,
struct inode * inode; struct inode * inode;
int err; int err;
inode_inc_link_count(dir); inode = minix_new_inode(dir, S_IFDIR | mode);
if (IS_ERR(inode))
inode = minix_new_inode(dir, S_IFDIR | mode, &err); return PTR_ERR(inode);
if (!inode)
goto out_dir;
inode_inc_link_count(dir);
minix_set_inode(inode, 0); minix_set_inode(inode, 0);
inode_inc_link_count(inode); inode_inc_link_count(inode);
err = minix_make_empty(inode, dir); err = minix_make_empty(inode, dir);
...@@ -143,30 +134,29 @@ static int minix_mkdir(struct mnt_idmap *idmap, struct 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);
inode_dec_link_count(inode); inode_dec_link_count(inode);
iput(inode); iput(inode);
out_dir:
inode_dec_link_count(dir); inode_dec_link_count(dir);
goto out; goto out;
} }
static int minix_unlink(struct inode * dir, struct dentry *dentry) static int minix_unlink(struct inode * dir, struct dentry *dentry)
{ {
int err = -ENOENT;
struct inode * inode = d_inode(dentry); struct inode * inode = d_inode(dentry);
struct page * page; struct page * page;
struct minix_dir_entry * de; struct minix_dir_entry * de;
int err;
de = minix_find_entry(dentry, &page); de = minix_find_entry(dentry, &page);
if (!de) if (!de)
goto end_unlink; return -ENOENT;
err = minix_delete_entry(de, page); err = minix_delete_entry(de, page);
if (err) kunmap(page);
goto end_unlink; put_page(page);
if (err)
return err;
inode->i_ctime = dir->i_ctime; inode->i_ctime = dir->i_ctime;
inode_dec_link_count(inode); inode_dec_link_count(inode);
end_unlink: return 0;
return err;
} }
static int minix_rmdir(struct inode * dir, struct dentry *dentry) static int minix_rmdir(struct inode * dir, struct dentry *dentry)
...@@ -223,7 +213,11 @@ static int minix_rename(struct mnt_idmap *idmap, ...@@ -223,7 +213,11 @@ static int minix_rename(struct mnt_idmap *idmap,
new_de = minix_find_entry(new_dentry, &new_page); new_de = minix_find_entry(new_dentry, &new_page);
if (!new_de) if (!new_de)
goto out_dir; 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); new_inode->i_ctime = current_time(new_inode);
if (dir_de) if (dir_de)
drop_nlink(new_inode); drop_nlink(new_inode);
...@@ -236,15 +230,17 @@ static int minix_rename(struct mnt_idmap *idmap, ...@@ -236,15 +230,17 @@ static int minix_rename(struct mnt_idmap *idmap,
inode_inc_link_count(new_dir); 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); mark_inode_dirty(old_inode);
if (dir_de) { 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); inode_dec_link_count(old_dir);
} }
return 0;
out_dir: out_dir:
if (dir_de) { if (dir_de) {
kunmap(dir_page); kunmap(dir_page);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment