diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2023-02-24 19:01:15 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2023-02-24 19:01:15 -0800 |
commit | 397aa6b63ff25cee0b8ed20a6d447527c8ab0849 (patch) | |
tree | b3146e8c494b00624597e400f0d2a9a8edd36d4a /fs | |
parent | 595fa4e313fee3c0b69c10bbed6fffb803237306 (diff) | |
parent | 2cb6a44220b974a7832d1a09630b4cee870b023a (diff) | |
download | linux-stable-397aa6b63ff25cee0b8ed20a6d447527c8ab0849.tar.gz linux-stable-397aa6b63ff25cee0b8ed20a6d447527c8ab0849.tar.bz2 linux-stable-397aa6b63ff25cee0b8ed20a6d447527c8ab0849.zip |
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...)
Diffstat (limited to 'fs')
-rw-r--r-- | fs/minix/bitmap.c | 16 | ||||
-rw-r--r-- | fs/minix/dir.c | 62 | ||||
-rw-r--r-- | fs/minix/minix.h | 5 | ||||
-rw-r--r-- | fs/minix/namei.c | 100 |
4 files changed, 91 insertions, 92 deletions
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c index 724d8191a310..870207ba23f1 100644 --- a/fs/minix/bitmap.c +++ b/fs/minix/bitmap.c @@ -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; } diff --git a/fs/minix/dir.c b/fs/minix/dir.c index dcfe5b25378b..bf9858f76b6a 100644 --- a/fs/minix/dir.c +++ b/fs/minix/dir.c @@ -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); + 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 @@ got_it: 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 (sbi->s_version == MINIX_V3) - ((minix3_dirent *) de)->inode = 0; - else - de->inode = 0; - err = dir_commit_chunk(page, pos, len); - } else { + if (err) { 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); 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,8 +416,8 @@ not_empty: } /* Releases the page */ -void minix_set_link(struct minix_dir_entry *de, struct page *page, - struct inode *inode) +int minix_set_link(struct minix_dir_entry *de, struct page *page, + struct inode *inode) { struct inode *dir = page->mapping->host; 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; lock_page(page); - err = minix_prepare_chunk(page, pos, sbi->s_dirsize); - if (err == 0) { - 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 { + if (err) { 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); mark_inode_dirty(dir); + return minix_handle_dirsync(dir); } struct minix_dir_entry * minix_dotdot (struct inode *dir, struct page **p) diff --git a/fs/minix/minix.h b/fs/minix/minix.h index e0b76defa85c..d493507c064f 100644 --- a/fs/minix/minix.h +++ b/fs/minix/minix.h @@ -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*); diff --git a/fs/minix/namei.c b/fs/minix/namei.c index 39ebe10d6a8b..956d5183828d 100644 --- a/fs/minix/namei.c +++ b/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, 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; + minix_set_inode(inode, rdev); + mark_inode_dirty(inode); + 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) { - minix_set_inode(inode, 0); - mark_inode_dirty(inode); - d_tmpfile(file, inode); - } - return finish_open_simple(file, error); + 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, 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: - inode_dec_link_count(inode); - iput(inode); - goto out; + if (unlikely(err)) { + inode_dec_link_count(inode); + iput(inode); + 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 @@ out_fail: 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); - inode_dec_link_count(old_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); |