]> Git Repo - linux.git/blobdiff - fs/btrfs/file.c
btrfs: fix abort logic in btrfs_replace_file_extents
[linux.git] / fs / btrfs / file.c
index ee34497500e169415efdb47817c5af65260aebfd..a1762363f61faff8248c9fc4e7cda9503c775da5 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/btrfs.h>
 #include <linux/uio.h>
 #include <linux/iversion.h>
+#include <linux/fsverity.h>
 #include "ctree.h"
 #include "disk-io.h"
 #include "transaction.h"
@@ -733,8 +734,7 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans,
        if (args->start >= inode->disk_i_size && !args->replace_extent)
                modify_tree = 0;
 
-       update_refs = (test_bit(BTRFS_ROOT_SHAREABLE, &root->state) ||
-                      root == fs_info->tree_root);
+       update_refs = (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID);
        while (1) {
                recow = 0;
                ret = btrfs_lookup_file_extent(trans, root, path, ino,
@@ -1340,7 +1340,18 @@ static int prepare_uptodate_page(struct inode *inode,
                        unlock_page(page);
                        return -EIO;
                }
-               if (page->mapping != inode->i_mapping) {
+
+               /*
+                * Since btrfs_readpage() will unlock the page before it
+                * returns, there is a window where btrfs_releasepage() can be
+                * called to release the page.  Here we check both inode
+                * mapping and PagePrivate() to make sure the page was not
+                * released.
+                *
+                * The private flag check is essential for subpage as we need
+                * to store extra bitmap using page->private.
+                */
+               if (page->mapping != inode->i_mapping || !PagePrivate(page)) {
                        unlock_page(page);
                        return -EAGAIN;
                }
@@ -2692,14 +2703,16 @@ int btrfs_replace_file_extents(struct btrfs_inode *inode,
                                                 drop_args.bytes_found);
                if (ret != -ENOSPC) {
                        /*
-                        * When cloning we want to avoid transaction aborts when
-                        * nothing was done and we are attempting to clone parts
-                        * of inline extents, in such cases -EOPNOTSUPP is
-                        * returned by __btrfs_drop_extents() without having
-                        * changed anything in the file.
+                        * The only time we don't want to abort is if we are
+                        * attempting to clone a partial inline extent, in which
+                        * case we'll get EOPNOTSUPP.  However if we aren't
+                        * clone we need to abort no matter what, because if we
+                        * got EOPNOTSUPP via prealloc then we messed up and
+                        * need to abort.
                         */
-                       if (extent_info && !extent_info->is_new_extent &&
-                           ret && ret != -EOPNOTSUPP)
+                       if (ret &&
+                           (ret != -EOPNOTSUPP ||
+                            (extent_info && extent_info->is_new_extent)))
                                btrfs_abort_transaction(trans, ret);
                        break;
                }
@@ -3604,7 +3617,13 @@ static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int whence)
 
 static int btrfs_file_open(struct inode *inode, struct file *filp)
 {
+       int ret;
+
        filp->f_mode |= FMODE_NOWAIT | FMODE_BUF_RASYNC;
+
+       ret = fsverity_file_open(inode, filp);
+       if (ret)
+               return ret;
        return generic_file_open(inode, filp);
 }
 
@@ -3633,6 +3652,9 @@ static ssize_t btrfs_direct_read(struct kiocb *iocb, struct iov_iter *to)
        struct inode *inode = file_inode(iocb->ki_filp);
        ssize_t ret;
 
+       if (fsverity_active(inode))
+               return 0;
+
        if (check_direct_read(btrfs_sb(inode->i_sb), to, iocb->ki_pos))
                return 0;
 
This page took 0.033885 seconds and 4 git commands to generate.