mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-06 13:23:18 +00:00
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...)
This commit is contained in:
commit
397aa6b63f
@ -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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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))
|
unlock_page(page);
|
||||||
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;
|
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);
|
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)
|
|||||||
|
|
||||||
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) {
|
||||||
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);
|
unlock_page(page);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
dir_put_page(page);
|
if (sbi->s_version == MINIX_V3)
|
||||||
|
((minix3_dirent *)de)->inode = 0;
|
||||||
|
else
|
||||||
|
de->inode = 0;
|
||||||
|
dir_commit_chunk(page, pos, len);
|
||||||
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)
|
|||||||
}
|
}
|
||||||
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,8 +416,8 @@ 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;
|
||||||
struct minix_sb_info *sbi = minix_sb(dir->i_sb);
|
struct minix_sb_info *sbi = minix_sb(dir->i_sb);
|
||||||
@ -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) {
|
||||||
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);
|
unlock_page(page);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
dir_put_page(page);
|
if (sbi->s_version == MINIX_V3)
|
||||||
|
((minix3_dirent *)de)->inode = inode->i_ino;
|
||||||
|
else
|
||||||
|
de->inode = inode->i_ino;
|
||||||
|
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);
|
||||||
|
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 {
|
|||||||
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*);
|
|||||||
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*);
|
||||||
|
|
||||||
|
100
fs/minix/namei.c
100
fs/minix/namei.c
@ -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);
|
return add_nondir(dentry, inode);
|
||||||
error = 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))
|
||||||
minix_set_inode(inode, 0);
|
return finish_open_simple(file, PTR_ERR(inode));
|
||||||
mark_inode_dirty(inode);
|
minix_set_inode(inode, 0);
|
||||||
d_tmpfile(file, inode);
|
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,
|
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;
|
inode_dec_link_count(inode);
|
||||||
|
iput(inode);
|
||||||
err = add_nondir(dentry, inode);
|
return err;
|
||||||
out:
|
}
|
||||||
return err;
|
return add_nondir(dentry, inode);
|
||||||
|
|
||||||
out_fail:
|
|
||||||
inode_dec_link_count(inode);
|
|
||||||
iput(inode);
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|||||||
struct inode * inode;
|
struct inode * inode;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
inode = minix_new_inode(dir, S_IFDIR | mode);
|
||||||
|
if (IS_ERR(inode))
|
||||||
|
return PTR_ERR(inode);
|
||||||
|
|
||||||
inode_inc_link_count(dir);
|
inode_inc_link_count(dir);
|
||||||
|
|
||||||
inode = minix_new_inode(dir, S_IFDIR | mode, &err);
|
|
||||||
if (!inode)
|
|
||||||
goto out_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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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);
|
||||||
inode_dec_link_count(old_dir);
|
if (!err)
|
||||||
|
inode_dec_link_count(old_dir);
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
|
||||||
out_dir:
|
out_dir:
|
||||||
if (dir_de) {
|
if (dir_de) {
|
||||||
kunmap(dir_page);
|
kunmap(dir_page);
|
||||||
|
Loading…
Reference in New Issue
Block a user