]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blobdiff - fs/read_write.c
mm: vmalloc: show number of vmalloc pages in /proc/meminfo
[mirror_ubuntu-hirsute-kernel.git] / fs / read_write.c
index b63dcb4e4fe979da170d91018ff2b81c1aa3cc3a..1f5088dec566b71a37f697edd7419b7813edbb4c 100644 (file)
@@ -1599,7 +1599,16 @@ static ssize_t do_copy_file_range(struct file *file_in, loff_t pos_in,
                                  struct file *file_out, loff_t pos_out,
                                  size_t len, unsigned int flags)
 {
-       if (file_out->f_op->copy_file_range)
+       /*
+        * Although we now allow filesystems to handle cross sb copy, passing
+        * a file of the wrong filesystem type to filesystem driver can result
+        * in an attempt to dereference the wrong type of ->private_data, so
+        * avoid doing that until we really have a good reason.  NFS defines
+        * several different file_system_type structures, but they all end up
+        * using the same ->copy_file_range() function pointer.
+        */
+       if (file_out->f_op->copy_file_range &&
+           file_out->f_op->copy_file_range == file_in->f_op->copy_file_range)
                return file_out->f_op->copy_file_range(file_in, pos_in,
                                                       file_out, pos_out,
                                                       len, flags);
@@ -1617,17 +1626,15 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
                            struct file *file_out, loff_t pos_out,
                            size_t len, unsigned int flags)
 {
-       struct inode *inode_in = file_inode(file_in);
-       struct inode *inode_out = file_inode(file_out);
        ssize_t ret;
 
        if (flags != 0)
                return -EINVAL;
 
-       if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode))
-               return -EISDIR;
-       if (!S_ISREG(inode_in->i_mode) || !S_ISREG(inode_out->i_mode))
-               return -EINVAL;
+       ret = generic_copy_file_checks(file_in, pos_in, file_out, pos_out, &len,
+                                      flags);
+       if (unlikely(ret))
+               return ret;
 
        ret = rw_verify_area(READ, file_in, &pos_in, len);
        if (unlikely(ret))
@@ -1637,15 +1644,6 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
        if (unlikely(ret))
                return ret;
 
-       if (!(file_in->f_mode & FMODE_READ) ||
-           !(file_out->f_mode & FMODE_WRITE) ||
-           (file_out->f_flags & O_APPEND))
-               return -EBADF;
-
-       /* this could be relaxed once a method supports cross-fs copies */
-       if (inode_in->i_sb != inode_out->i_sb)
-               return -EXDEV;
-
        if (len == 0)
                return 0;
 
@@ -1655,7 +1653,8 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
         * Try cloning first, this is supported by more file systems, and
         * more efficient if both clone and copy are supported (e.g. NFS).
         */
-       if (file_in->f_op->remap_file_range) {
+       if (file_in->f_op->remap_file_range &&
+           file_inode(file_in)->i_sb == file_inode(file_out)->i_sb) {
                loff_t cloned;
 
                cloned = file_in->f_op->remap_file_range(file_in, pos_in,
@@ -1987,25 +1986,10 @@ int generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
                return ret;
 
        /* If can't alter the file contents, we're done. */
-       if (!(remap_flags & REMAP_FILE_DEDUP)) {
-               /* Update the timestamps, since we can alter file contents. */
-               if (!(file_out->f_mode & FMODE_NOCMTIME)) {
-                       ret = file_update_time(file_out);
-                       if (ret)
-                               return ret;
-               }
-
-               /*
-                * Clear the security bits if the process is not being run by
-                * root.  This keeps people from modifying setuid and setgid
-                * binaries.
-                */
-               ret = file_remove_privs(file_out);
-               if (ret)
-                       return ret;
-       }
+       if (!(remap_flags & REMAP_FILE_DEDUP))
+               ret = file_modified(file_out);
 
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL(generic_remap_file_range_prep);
 
@@ -2013,29 +1997,21 @@ loff_t do_clone_file_range(struct file *file_in, loff_t pos_in,
                           struct file *file_out, loff_t pos_out,
                           loff_t len, unsigned int remap_flags)
 {
-       struct inode *inode_in = file_inode(file_in);
-       struct inode *inode_out = file_inode(file_out);
        loff_t ret;
 
        WARN_ON_ONCE(remap_flags & REMAP_FILE_DEDUP);
 
-       if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode))
-               return -EISDIR;
-       if (!S_ISREG(inode_in->i_mode) || !S_ISREG(inode_out->i_mode))
-               return -EINVAL;
-
        /*
         * FICLONE/FICLONERANGE ioctls enforce that src and dest files are on
         * the same mount. Practically, they only need to be on the same file
         * system.
         */
-       if (inode_in->i_sb != inode_out->i_sb)
+       if (file_inode(file_in)->i_sb != file_inode(file_out)->i_sb)
                return -EXDEV;
 
-       if (!(file_in->f_mode & FMODE_READ) ||
-           !(file_out->f_mode & FMODE_WRITE) ||
-           (file_out->f_flags & O_APPEND))
-               return -EBADF;
+       ret = generic_file_rw_checks(file_in, file_out);
+       if (ret < 0)
+               return ret;
 
        if (!file_in->f_op->remap_file_range)
                return -EOPNOTSUPP;