Commit eb3a6d15 authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] hpfs: new/read/write_inode() cleanups

	1) common initialization for all paths in hpfs_read_inode() taken into
a separate helper (hpfs_init_inode())
	2) hpfs mkdir(),create(),mknod() and symlink() do not bother with
iget() anymore - they call new_inode(), do initializations and insert new
inode into icache.  Handling of OOM failures cleaned up - if we can't
allocate in-core inode, bail instead of corrupting the filesystem.
Allocating in-core inode early also avoids one of the deadlocks here
(hpfs_write_inode() from memory pressure by kmem_cache_alloc() could
deadlock on attempt to lock our directory).
	3) hpfs_write_inode() marks the inode dirty again in case if it
fails to iget() its parent directory.  Again, OOM could trigger fs corruption
here.
parent fde48def
......@@ -249,6 +249,7 @@ ssize_t hpfs_file_write(struct file *file, const char __user *buf, size_t count,
/* inode.c */
void hpfs_init_inode(struct inode *);
void hpfs_read_inode(struct inode *);
void hpfs_write_inode_ea(struct inode *, struct fnode *);
void hpfs_write_inode(struct inode *);
......
......@@ -57,14 +57,10 @@ struct address_space_operations hpfs_symlink_aops = {
.readpage = hpfs_symlink_readpage
};
void hpfs_read_inode(struct inode *i)
void hpfs_init_inode(struct inode *i)
{
struct buffer_head *bh;
struct fnode *fnode;
struct super_block *sb = i->i_sb;
struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
unsigned char *ea;
int ea_size;
i->i_uid = hpfs_sb(sb)->sb_uid;
i->i_gid = hpfs_sb(sb)->sb_gid;
......@@ -91,6 +87,18 @@ void hpfs_read_inode(struct inode *i)
i->i_ctime.tv_sec = i->i_ctime.tv_nsec = 0;
i->i_mtime.tv_sec = i->i_mtime.tv_nsec = 0;
i->i_atime.tv_sec = i->i_atime.tv_nsec = 0;
}
void hpfs_read_inode(struct inode *i)
{
struct buffer_head *bh;
struct fnode *fnode;
struct super_block *sb = i->i_sb;
struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
unsigned char *ea;
int ea_size;
hpfs_init_inode(i);
if (!hpfs_sb(i->i_sb)->sb_rd_inode)
hpfs_error(i->i_sb, "read_inode: sb_rd_inode == 0");
......@@ -240,14 +248,19 @@ void hpfs_write_inode(struct inode *i)
kfree(hpfs_inode->i_rddir_off);
hpfs_inode->i_rddir_off = NULL;
}
hpfs_inode->i_dirty = 0;
hpfs_lock_iget(i->i_sb, 1);
parent = iget(i->i_sb, hpfs_inode->i_parent_dir);
if (parent) {
hpfs_unlock_iget(i->i_sb);
hpfs_inode->i_dirty = 0;
hpfs_lock_inode(parent);
hpfs_write_inode_nolock(i);
hpfs_unlock_inode(parent);
iput(parent);
} else {
hpfs_unlock_iget(i->i_sb);
mark_inode_dirty(i);
}
}
void hpfs_write_inode_nolock(struct inode *i)
......
......@@ -42,13 +42,34 @@ int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
dee.hidden = name[0] == '.';
dee.fnode = fno;
dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds());
result = new_inode(dir->i_sb);
if (!result)
goto bail2;
hpfs_init_inode(result);
result->i_ino = fno;
hpfs_i(result)->i_parent_dir = dir->i_ino;
hpfs_i(result)->i_dno = dno;
result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date);
result->i_ctime.tv_nsec = 0;
result->i_mtime.tv_nsec = 0;
result->i_atime.tv_nsec = 0;
hpfs_i(result)->i_ea_size = 0;
result->i_mode |= S_IFDIR;
result->i_op = &hpfs_dir_iops;
result->i_fop = &hpfs_dir_ops;
result->i_blocks = 4;
result->i_size = 2048;
result->i_nlink = 2;
if (dee.read_only)
result->i_mode &= ~0222;
hpfs_lock_inode(dir);
r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0);
if (r == 1)
goto bail2;
goto bail3;
if (r == -1) {
err = -EEXIST;
goto bail2;
goto bail3;
}
fnode->len = len;
memcpy(fnode->name, name, len > 15 ? 15 : len);
......@@ -72,15 +93,8 @@ int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
hpfs_mark_4buffers_dirty(&qbh0);
hpfs_brelse4(&qbh0);
dir->i_nlink++;
hpfs_lock_iget(dir->i_sb, 1);
if ((result = iget(dir->i_sb, fno))) {
hpfs_i(result)->i_parent_dir = dir->i_ino;
result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date);
result->i_ctime.tv_nsec = 0;
result->i_mtime.tv_nsec = 0;
result->i_atime.tv_nsec = 0;
hpfs_i(result)->i_ea_size = 0;
if (dee.read_only) result->i_mode &= ~0222;
insert_inode_hash(result);
if (result->i_uid != current->fsuid ||
result->i_gid != current->fsgid ||
result->i_mode != (mode | S_IFDIR)) {
......@@ -90,15 +104,15 @@ int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
hpfs_write_inode_nolock(result);
}
d_instantiate(dentry, result);
}
hpfs_unlock_iget(dir->i_sb);
hpfs_unlock_inode(dir);
unlock_kernel();
return 0;
bail3:
hpfs_unlock_inode(dir);
iput(result);
bail2:
hpfs_brelse4(&qbh0);
hpfs_free_dnode(dir->i_sb, dno);
hpfs_unlock_inode(dir);
bail1:
brelse(bh);
hpfs_free_sectors(dir->i_sb, fno, 1);
......@@ -131,21 +145,18 @@ int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struct namei
dee.hidden = name[0] == '.';
dee.fnode = fno;
dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds());
hpfs_lock_inode(dir);
r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0);
if (r == 1)
goto bail1;
if (r == -1) {
err = -EEXIST;
result = new_inode(dir->i_sb);
if (!result)
goto bail1;
}
fnode->len = len;
memcpy(fnode->name, name, len > 15 ? 15 : len);
fnode->up = dir->i_ino;
mark_buffer_dirty(bh);
brelse(bh);
hpfs_lock_iget(dir->i_sb, 2);
if ((result = iget(dir->i_sb, fno))) {
hpfs_init_inode(result);
result->i_ino = fno;
result->i_mode |= S_IFREG;
result->i_mode &= ~0111;
result->i_op = &hpfs_file_iops;
result->i_fop = &hpfs_file_ops;
result->i_nlink = 1;
hpfs_decide_conv(result, (char *)name, len);
hpfs_i(result)->i_parent_dir = dir->i_ino;
result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date);
......@@ -153,13 +164,29 @@ int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struct namei
result->i_mtime.tv_nsec = 0;
result->i_atime.tv_nsec = 0;
hpfs_i(result)->i_ea_size = 0;
if (dee.read_only) result->i_mode &= ~0222;
if (result->i_blocks == -1) result->i_blocks = 1;
if (result->i_size == -1) {
if (dee.read_only)
result->i_mode &= ~0222;
result->i_blocks = 1;
result->i_size = 0;
result->i_data.a_ops = &hpfs_aops;
hpfs_i(result)->mmu_private = 0;
hpfs_lock_inode(dir);
r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0);
if (r == 1)
goto bail2;
if (r == -1) {
err = -EEXIST;
goto bail2;
}
fnode->len = len;
memcpy(fnode->name, name, len > 15 ? 15 : len);
fnode->up = dir->i_ino;
mark_buffer_dirty(bh);
brelse(bh);
insert_inode_hash(result);
if (result->i_uid != current->fsuid ||
result->i_gid != current->fsgid ||
result->i_mode != (mode | S_IFREG)) {
......@@ -169,15 +196,16 @@ int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struct namei
hpfs_write_inode_nolock(result);
}
d_instantiate(dentry, result);
}
hpfs_unlock_iget(dir->i_sb);
hpfs_unlock_inode(dir);
unlock_kernel();
return 0;
bail2:
hpfs_unlock_inode(dir);
iput(result);
bail1:
brelse(bh);
hpfs_free_sectors(dir->i_sb, fno, 1);
hpfs_unlock_inode(dir);
bail:
unlock_kernel();
return err;
......@@ -209,46 +237,53 @@ int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
dee.hidden = name[0] == '.';
dee.fnode = fno;
dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds());
hpfs_lock_inode(dir);
r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0);
if (r == 1)
goto bail1;
if (r == -1) {
err = -EEXIST;
result = new_inode(dir->i_sb);
if (!result)
goto bail1;
}
fnode->len = len;
memcpy(fnode->name, name, len > 15 ? 15 : len);
fnode->up = dir->i_ino;
mark_buffer_dirty(bh);
hpfs_lock_iget(dir->i_sb, 2);
if ((result = iget(dir->i_sb, fno))) {
hpfs_init_inode(result);
result->i_ino = fno;
hpfs_i(result)->i_parent_dir = dir->i_ino;
result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date);
result->i_ctime.tv_nsec = 0;
result->i_mtime.tv_nsec = 0;
result->i_atime.tv_nsec = 0;
hpfs_i(result)->i_ea_size = 0;
/*if (result->i_blocks == -1) result->i_blocks = 1;
if (result->i_size == -1) result->i_size = 0;*/
result->i_uid = current->fsuid;
result->i_gid = current->fsgid;
result->i_nlink = 1;
result->i_size = 0;
result->i_blocks = 1;
init_special_inode(result, mode, rdev);
hpfs_lock_inode(dir);
r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0);
if (r == 1)
goto bail2;
if (r == -1) {
err = -EEXIST;
goto bail2;
}
fnode->len = len;
memcpy(fnode->name, name, len > 15 ? 15 : len);
fnode->up = dir->i_ino;
mark_buffer_dirty(bh);
insert_inode_hash(result);
hpfs_write_inode_nolock(result);
d_instantiate(dentry, result);
}
hpfs_unlock_iget(dir->i_sb);
hpfs_unlock_inode(dir);
brelse(bh);
unlock_kernel();
return 0;
bail2:
hpfs_unlock_inode(dir);
iput(result);
bail1:
brelse(bh);
hpfs_free_sectors(dir->i_sb, fno, 1);
hpfs_unlock_inode(dir);
bail:
unlock_kernel();
return err;
......@@ -282,52 +317,55 @@ int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *symlink)
dee.hidden = name[0] == '.';
dee.fnode = fno;
dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds());
hpfs_lock_inode(dir);
r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0);
if (r == 1)
goto bail1;
if (r == -1) {
err = -EEXIST;
result = new_inode(dir->i_sb);
if (!result)
goto bail1;
}
fnode->len = len;
memcpy(fnode->name, name, len > 15 ? 15 : len);
fnode->up = dir->i_ino;
mark_buffer_dirty(bh);
brelse(bh);
hpfs_lock_iget(dir->i_sb, 2);
if ((result = iget(dir->i_sb, fno))) {
result->i_ino = fno;
hpfs_init_inode(result);
hpfs_i(result)->i_parent_dir = dir->i_ino;
result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date);
result->i_ctime.tv_nsec = 0;
result->i_mtime.tv_nsec = 0;
result->i_atime.tv_nsec = 0;
hpfs_i(result)->i_ea_size = 0;
/*if (result->i_blocks == -1) result->i_blocks = 1;
if (result->i_size == -1) result->i_size = 0;*/
result->i_mode = S_IFLNK | 0777;
result->i_uid = current->fsuid;
result->i_gid = current->fsgid;
result->i_blocks = 1;
result->i_nlink = 1;
result->i_size = strlen(symlink);
result->i_op = &page_symlink_inode_operations;
result->i_data.a_ops = &hpfs_symlink_aops;
if ((fnode = hpfs_map_fnode(dir->i_sb, fno, &bh))) {
hpfs_lock_inode(dir);
r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0);
if (r == 1)
goto bail2;
if (r == -1) {
err = -EEXIST;
goto bail2;
}
fnode->len = len;
memcpy(fnode->name, name, len > 15 ? 15 : len);
fnode->up = dir->i_ino;
hpfs_set_ea(result, fnode, "SYMLINK", (char *)symlink, strlen(symlink));
mark_buffer_dirty(bh);
brelse(bh);
}
insert_inode_hash(result);
hpfs_write_inode_nolock(result);
d_instantiate(dentry, result);
}
hpfs_unlock_iget(dir->i_sb);
hpfs_unlock_inode(dir);
unlock_kernel();
return 0;
bail2:
hpfs_unlock_inode(dir);
iput(result);
bail1:
brelse(bh);
hpfs_free_sectors(dir->i_sb, fno, 1);
hpfs_unlock_inode(dir);
bail:
unlock_kernel();
return err;
......
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