Merge branch 'work.minix' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 25 Feb 2023 03:01:15 +0000 (19:01 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 25 Feb 2023 03:01:15 +0000 (19:01 -0800)
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...)

fs/minix/bitmap.c
fs/minix/dir.c
fs/minix/minix.h
fs/minix/namei.c

index 724d8191a31012c0ff35926742ea65aa7f6c7ce8..870207ba23f1c46acd30ebcad7c63c8243db9049 100644 (file)
@@ -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;
 }
 
index dcfe5b25378b54242d781ed7aaae23d6678379a3..bf9858f76b6ae1d1d68249964587e638d76564f7 100644 (file)
@@ -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)
index e0b76defa85c42e47002bbefb081f3e2a4db411f..d493507c064f6709d5df1c6af174b2d9e9591d36 100644 (file)
@@ -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*);
 
index 39ebe10d6a8bd1d2d40203ee033c92fa2dcaa94e..956d5183828dcbf0ce3371df09b2b1d6c4ebf7f0 100644 (file)
@@ -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);