LCOV - code coverage report
Current view: top level - fs/overlayfs - file.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 33 350 9.4 %
Date: 2021-04-22 12:43:58 Functions: 4 26 15.4 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-only
       2             : /*
       3             :  * Copyright (C) 2017 Red Hat, Inc.
       4             :  */
       5             : 
       6             : #include <linux/cred.h>
       7             : #include <linux/file.h>
       8             : #include <linux/mount.h>
       9             : #include <linux/xattr.h>
      10             : #include <linux/uio.h>
      11             : #include <linux/uaccess.h>
      12             : #include <linux/splice.h>
      13             : #include <linux/security.h>
      14             : #include <linux/mm.h>
      15             : #include <linux/fs.h>
      16             : #include "overlayfs.h"
      17             : 
      18             : struct ovl_aio_req {
      19             :         struct kiocb iocb;
      20             :         struct kiocb *orig_iocb;
      21             :         struct fd fd;
      22             : };
      23             : 
      24             : static struct kmem_cache *ovl_aio_request_cachep;
      25             : 
      26             : static char ovl_whatisit(struct inode *inode, struct inode *realinode)
      27             : {
      28             :         if (realinode != ovl_inode_upper(inode))
      29             :                 return 'l';
      30             :         if (ovl_has_upperdata(inode))
      31             :                 return 'u';
      32             :         else
      33             :                 return 'm';
      34             : }
      35             : 
      36             : /* No atime modificaton nor notify on underlying */
      37             : #define OVL_OPEN_FLAGS (O_NOATIME | FMODE_NONOTIFY)
      38             : 
      39          39 : static struct file *ovl_open_realfile(const struct file *file,
      40             :                                       struct inode *realinode)
      41             : {
      42          39 :         struct inode *inode = file_inode(file);
      43          39 :         struct file *realfile;
      44          39 :         const struct cred *old_cred;
      45          39 :         int flags = file->f_flags | OVL_OPEN_FLAGS;
      46          39 :         int acc_mode = ACC_MODE(flags);
      47          39 :         int err;
      48             : 
      49          39 :         if (flags & O_APPEND)
      50           0 :                 acc_mode |= MAY_APPEND;
      51             : 
      52          39 :         old_cred = ovl_override_creds(inode->i_sb);
      53          39 :         err = inode_permission(&init_user_ns, realinode, MAY_OPEN | acc_mode);
      54          39 :         if (err) {
      55           0 :                 realfile = ERR_PTR(err);
      56             :         } else {
      57          39 :                 if (!inode_owner_or_capable(&init_user_ns, realinode))
      58           0 :                         flags &= ~O_NOATIME;
      59             : 
      60          39 :                 realfile = open_with_fake_path(&file->f_path, flags, realinode,
      61          39 :                                                current_cred());
      62             :         }
      63          39 :         revert_creds(old_cred);
      64             : 
      65          39 :         pr_debug("open(%p[%pD2/%c], 0%o) -> (%p, 0%o)\n",
      66             :                  file, file, ovl_whatisit(inode, realinode), file->f_flags,
      67             :                  realfile, IS_ERR(realfile) ? 0 : realfile->f_flags);
      68             : 
      69          39 :         return realfile;
      70             : }
      71             : 
      72             : #define OVL_SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT)
      73             : 
      74           0 : static int ovl_change_flags(struct file *file, unsigned int flags)
      75             : {
      76           0 :         struct inode *inode = file_inode(file);
      77           0 :         int err;
      78             : 
      79           0 :         flags &= OVL_SETFL_MASK;
      80             : 
      81           0 :         if (((flags ^ file->f_flags) & O_APPEND) && IS_APPEND(inode))
      82             :                 return -EPERM;
      83             : 
      84           0 :         if (flags & O_DIRECT) {
      85           0 :                 if (!file->f_mapping->a_ops ||
      86           0 :                     !file->f_mapping->a_ops->direct_IO)
      87             :                         return -EINVAL;
      88             :         }
      89             : 
      90           0 :         if (file->f_op->check_flags) {
      91           0 :                 err = file->f_op->check_flags(flags);
      92           0 :                 if (err)
      93             :                         return err;
      94             :         }
      95             : 
      96           0 :         spin_lock(&file->f_lock);
      97           0 :         file->f_flags = (file->f_flags & ~OVL_SETFL_MASK) | flags;
      98           0 :         spin_unlock(&file->f_lock);
      99             : 
     100           0 :         return 0;
     101             : }
     102             : 
     103           0 : static int ovl_real_fdget_meta(const struct file *file, struct fd *real,
     104             :                                bool allow_meta)
     105             : {
     106           0 :         struct inode *inode = file_inode(file);
     107           0 :         struct inode *realinode;
     108             : 
     109           0 :         real->flags = 0;
     110           0 :         real->file = file->private_data;
     111             : 
     112           0 :         if (allow_meta)
     113           0 :                 realinode = ovl_inode_real(inode);
     114             :         else
     115           0 :                 realinode = ovl_inode_realdata(inode);
     116             : 
     117             :         /* Has it been copied up since we'd opened it? */
     118           0 :         if (unlikely(file_inode(real->file) != realinode)) {
     119           0 :                 real->flags = FDPUT_FPUT;
     120           0 :                 real->file = ovl_open_realfile(file, realinode);
     121             : 
     122           0 :                 return PTR_ERR_OR_ZERO(real->file);
     123             :         }
     124             : 
     125             :         /* Did the flags change since open? */
     126           0 :         if (unlikely((file->f_flags ^ real->file->f_flags) & ~OVL_OPEN_FLAGS))
     127           0 :                 return ovl_change_flags(real->file, file->f_flags);
     128             : 
     129             :         return 0;
     130             : }
     131             : 
     132           0 : static int ovl_real_fdget(const struct file *file, struct fd *real)
     133             : {
     134           0 :         if (d_is_dir(file_dentry(file))) {
     135           0 :                 real->flags = 0;
     136           0 :                 real->file = ovl_dir_real_file(file, false);
     137             : 
     138           0 :                 return PTR_ERR_OR_ZERO(real->file);
     139             :         }
     140             : 
     141           0 :         return ovl_real_fdget_meta(file, real, false);
     142             : }
     143             : 
     144          39 : static int ovl_open(struct inode *inode, struct file *file)
     145             : {
     146          39 :         struct file *realfile;
     147          39 :         int err;
     148             : 
     149          39 :         err = ovl_maybe_copy_up(file_dentry(file), file->f_flags);
     150          39 :         if (err)
     151             :                 return err;
     152             : 
     153             :         /* No longer need these flags, so don't pass them on to underlying fs */
     154          39 :         file->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
     155             : 
     156          39 :         realfile = ovl_open_realfile(file, ovl_inode_realdata(inode));
     157          39 :         if (IS_ERR(realfile))
     158           0 :                 return PTR_ERR(realfile);
     159             : 
     160          39 :         file->private_data = realfile;
     161             : 
     162          39 :         return 0;
     163             : }
     164             : 
     165          39 : static int ovl_release(struct inode *inode, struct file *file)
     166             : {
     167          39 :         fput(file->private_data);
     168             : 
     169          39 :         return 0;
     170             : }
     171             : 
     172           0 : static loff_t ovl_llseek(struct file *file, loff_t offset, int whence)
     173             : {
     174           0 :         struct inode *inode = file_inode(file);
     175           0 :         struct fd real;
     176           0 :         const struct cred *old_cred;
     177           0 :         loff_t ret;
     178             : 
     179             :         /*
     180             :          * The two special cases below do not need to involve real fs,
     181             :          * so we can optimizing concurrent callers.
     182             :          */
     183           0 :         if (offset == 0) {
     184           0 :                 if (whence == SEEK_CUR)
     185           0 :                         return file->f_pos;
     186             : 
     187           0 :                 if (whence == SEEK_SET)
     188           0 :                         return vfs_setpos(file, 0, 0);
     189             :         }
     190             : 
     191           0 :         ret = ovl_real_fdget(file, &real);
     192           0 :         if (ret)
     193             :                 return ret;
     194             : 
     195             :         /*
     196             :          * Overlay file f_pos is the master copy that is preserved
     197             :          * through copy up and modified on read/write, but only real
     198             :          * fs knows how to SEEK_HOLE/SEEK_DATA and real fs may impose
     199             :          * limitations that are more strict than ->s_maxbytes for specific
     200             :          * files, so we use the real file to perform seeks.
     201             :          */
     202           0 :         ovl_inode_lock(inode);
     203           0 :         real.file->f_pos = file->f_pos;
     204             : 
     205           0 :         old_cred = ovl_override_creds(inode->i_sb);
     206           0 :         ret = vfs_llseek(real.file, offset, whence);
     207           0 :         revert_creds(old_cred);
     208             : 
     209           0 :         file->f_pos = real.file->f_pos;
     210           0 :         ovl_inode_unlock(inode);
     211             : 
     212           0 :         fdput(real);
     213             : 
     214           0 :         return ret;
     215             : }
     216             : 
     217           0 : static void ovl_file_accessed(struct file *file)
     218             : {
     219           0 :         struct inode *inode, *upperinode;
     220             : 
     221           0 :         if (file->f_flags & O_NOATIME)
     222             :                 return;
     223             : 
     224           0 :         inode = file_inode(file);
     225           0 :         upperinode = ovl_inode_upper(inode);
     226             : 
     227           0 :         if (!upperinode)
     228             :                 return;
     229             : 
     230           0 :         if ((!timespec64_equal(&inode->i_mtime, &upperinode->i_mtime) ||
     231           0 :              !timespec64_equal(&inode->i_ctime, &upperinode->i_ctime))) {
     232           0 :                 inode->i_mtime = upperinode->i_mtime;
     233           0 :                 inode->i_ctime = upperinode->i_ctime;
     234             :         }
     235             : 
     236           0 :         touch_atime(&file->f_path);
     237             : }
     238             : 
     239           0 : static rwf_t ovl_iocb_to_rwf(int ifl)
     240             : {
     241           0 :         rwf_t flags = 0;
     242             : 
     243           0 :         if (ifl & IOCB_NOWAIT)
     244           0 :                 flags |= RWF_NOWAIT;
     245           0 :         if (ifl & IOCB_HIPRI)
     246           0 :                 flags |= RWF_HIPRI;
     247           0 :         if (ifl & IOCB_DSYNC)
     248           0 :                 flags |= RWF_DSYNC;
     249           0 :         if (ifl & IOCB_SYNC)
     250           0 :                 flags |= RWF_SYNC;
     251             : 
     252           0 :         return flags;
     253             : }
     254             : 
     255           0 : static void ovl_aio_cleanup_handler(struct ovl_aio_req *aio_req)
     256             : {
     257           0 :         struct kiocb *iocb = &aio_req->iocb;
     258           0 :         struct kiocb *orig_iocb = aio_req->orig_iocb;
     259             : 
     260           0 :         if (iocb->ki_flags & IOCB_WRITE) {
     261           0 :                 struct inode *inode = file_inode(orig_iocb->ki_filp);
     262             : 
     263             :                 /* Actually acquired in ovl_write_iter() */
     264           0 :                 __sb_writers_acquired(file_inode(iocb->ki_filp)->i_sb,
     265             :                                       SB_FREEZE_WRITE);
     266           0 :                 file_end_write(iocb->ki_filp);
     267           0 :                 ovl_copyattr(ovl_inode_real(inode), inode);
     268             :         }
     269             : 
     270           0 :         orig_iocb->ki_pos = iocb->ki_pos;
     271           0 :         fdput(aio_req->fd);
     272           0 :         kmem_cache_free(ovl_aio_request_cachep, aio_req);
     273           0 : }
     274             : 
     275           0 : static void ovl_aio_rw_complete(struct kiocb *iocb, long res, long res2)
     276             : {
     277           0 :         struct ovl_aio_req *aio_req = container_of(iocb,
     278             :                                                    struct ovl_aio_req, iocb);
     279           0 :         struct kiocb *orig_iocb = aio_req->orig_iocb;
     280             : 
     281           0 :         ovl_aio_cleanup_handler(aio_req);
     282           0 :         orig_iocb->ki_complete(orig_iocb, res, res2);
     283           0 : }
     284             : 
     285           0 : static ssize_t ovl_read_iter(struct kiocb *iocb, struct iov_iter *iter)
     286             : {
     287           0 :         struct file *file = iocb->ki_filp;
     288           0 :         struct fd real;
     289           0 :         const struct cred *old_cred;
     290           0 :         ssize_t ret;
     291             : 
     292           0 :         if (!iov_iter_count(iter))
     293             :                 return 0;
     294             : 
     295           0 :         ret = ovl_real_fdget(file, &real);
     296           0 :         if (ret)
     297             :                 return ret;
     298             : 
     299           0 :         old_cred = ovl_override_creds(file_inode(file)->i_sb);
     300           0 :         if (is_sync_kiocb(iocb)) {
     301           0 :                 ret = vfs_iter_read(real.file, iter, &iocb->ki_pos,
     302             :                                     ovl_iocb_to_rwf(iocb->ki_flags));
     303             :         } else {
     304           0 :                 struct ovl_aio_req *aio_req;
     305             : 
     306           0 :                 ret = -ENOMEM;
     307           0 :                 aio_req = kmem_cache_zalloc(ovl_aio_request_cachep, GFP_KERNEL);
     308           0 :                 if (!aio_req)
     309           0 :                         goto out;
     310             : 
     311           0 :                 aio_req->fd = real;
     312           0 :                 real.flags = 0;
     313           0 :                 aio_req->orig_iocb = iocb;
     314           0 :                 kiocb_clone(&aio_req->iocb, iocb, real.file);
     315           0 :                 aio_req->iocb.ki_complete = ovl_aio_rw_complete;
     316           0 :                 ret = vfs_iocb_iter_read(real.file, &aio_req->iocb, iter);
     317           0 :                 if (ret != -EIOCBQUEUED)
     318           0 :                         ovl_aio_cleanup_handler(aio_req);
     319             :         }
     320           0 : out:
     321           0 :         revert_creds(old_cred);
     322           0 :         ovl_file_accessed(file);
     323             : 
     324           0 :         fdput(real);
     325             : 
     326           0 :         return ret;
     327             : }
     328             : 
     329           0 : static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter)
     330             : {
     331           0 :         struct file *file = iocb->ki_filp;
     332           0 :         struct inode *inode = file_inode(file);
     333           0 :         struct fd real;
     334           0 :         const struct cred *old_cred;
     335           0 :         ssize_t ret;
     336           0 :         int ifl = iocb->ki_flags;
     337             : 
     338           0 :         if (!iov_iter_count(iter))
     339             :                 return 0;
     340             : 
     341           0 :         inode_lock(inode);
     342             :         /* Update mode */
     343           0 :         ovl_copyattr(ovl_inode_real(inode), inode);
     344           0 :         ret = file_remove_privs(file);
     345           0 :         if (ret)
     346           0 :                 goto out_unlock;
     347             : 
     348           0 :         ret = ovl_real_fdget(file, &real);
     349           0 :         if (ret)
     350           0 :                 goto out_unlock;
     351             : 
     352           0 :         if (!ovl_should_sync(OVL_FS(inode->i_sb)))
     353           0 :                 ifl &= ~(IOCB_DSYNC | IOCB_SYNC);
     354             : 
     355           0 :         old_cred = ovl_override_creds(file_inode(file)->i_sb);
     356           0 :         if (is_sync_kiocb(iocb)) {
     357           0 :                 file_start_write(real.file);
     358           0 :                 ret = vfs_iter_write(real.file, iter, &iocb->ki_pos,
     359             :                                      ovl_iocb_to_rwf(ifl));
     360           0 :                 file_end_write(real.file);
     361             :                 /* Update size */
     362           0 :                 ovl_copyattr(ovl_inode_real(inode), inode);
     363             :         } else {
     364           0 :                 struct ovl_aio_req *aio_req;
     365             : 
     366           0 :                 ret = -ENOMEM;
     367           0 :                 aio_req = kmem_cache_zalloc(ovl_aio_request_cachep, GFP_KERNEL);
     368           0 :                 if (!aio_req)
     369           0 :                         goto out;
     370             : 
     371           0 :                 file_start_write(real.file);
     372             :                 /* Pacify lockdep, same trick as done in aio_write() */
     373           0 :                 __sb_writers_release(file_inode(real.file)->i_sb,
     374             :                                      SB_FREEZE_WRITE);
     375           0 :                 aio_req->fd = real;
     376           0 :                 real.flags = 0;
     377           0 :                 aio_req->orig_iocb = iocb;
     378           0 :                 kiocb_clone(&aio_req->iocb, iocb, real.file);
     379           0 :                 aio_req->iocb.ki_flags = ifl;
     380           0 :                 aio_req->iocb.ki_complete = ovl_aio_rw_complete;
     381           0 :                 ret = vfs_iocb_iter_write(real.file, &aio_req->iocb, iter);
     382           0 :                 if (ret != -EIOCBQUEUED)
     383           0 :                         ovl_aio_cleanup_handler(aio_req);
     384             :         }
     385           0 : out:
     386           0 :         revert_creds(old_cred);
     387           0 :         fdput(real);
     388             : 
     389           0 : out_unlock:
     390           0 :         inode_unlock(inode);
     391             : 
     392           0 :         return ret;
     393             : }
     394             : 
     395           0 : static int ovl_fsync(struct file *file, loff_t start, loff_t end, int datasync)
     396             : {
     397           0 :         struct fd real;
     398           0 :         const struct cred *old_cred;
     399           0 :         int ret;
     400             : 
     401           0 :         ret = ovl_sync_status(OVL_FS(file_inode(file)->i_sb));
     402           0 :         if (ret <= 0)
     403             :                 return ret;
     404             : 
     405           0 :         ret = ovl_real_fdget_meta(file, &real, !datasync);
     406           0 :         if (ret)
     407             :                 return ret;
     408             : 
     409             :         /* Don't sync lower file for fear of receiving EROFS error */
     410           0 :         if (file_inode(real.file) == ovl_inode_upper(file_inode(file))) {
     411           0 :                 old_cred = ovl_override_creds(file_inode(file)->i_sb);
     412           0 :                 ret = vfs_fsync_range(real.file, start, end, datasync);
     413           0 :                 revert_creds(old_cred);
     414             :         }
     415             : 
     416           0 :         fdput(real);
     417             : 
     418           0 :         return ret;
     419             : }
     420             : 
     421           0 : static int ovl_mmap(struct file *file, struct vm_area_struct *vma)
     422             : {
     423           0 :         struct file *realfile = file->private_data;
     424           0 :         const struct cred *old_cred;
     425           0 :         int ret;
     426             : 
     427           0 :         if (!realfile->f_op->mmap)
     428             :                 return -ENODEV;
     429             : 
     430           0 :         if (WARN_ON(file != vma->vm_file))
     431             :                 return -EIO;
     432             : 
     433           0 :         vma->vm_file = get_file(realfile);
     434             : 
     435           0 :         old_cred = ovl_override_creds(file_inode(file)->i_sb);
     436           0 :         ret = call_mmap(vma->vm_file, vma);
     437           0 :         revert_creds(old_cred);
     438             : 
     439           0 :         if (ret) {
     440             :                 /* Drop reference count from new vm_file value */
     441           0 :                 fput(realfile);
     442             :         } else {
     443             :                 /* Drop reference count from previous vm_file value */
     444           0 :                 fput(file);
     445             :         }
     446             : 
     447           0 :         ovl_file_accessed(file);
     448             : 
     449           0 :         return ret;
     450             : }
     451             : 
     452           0 : static long ovl_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
     453             : {
     454           0 :         struct inode *inode = file_inode(file);
     455           0 :         struct fd real;
     456           0 :         const struct cred *old_cred;
     457           0 :         int ret;
     458             : 
     459           0 :         ret = ovl_real_fdget(file, &real);
     460           0 :         if (ret)
     461           0 :                 return ret;
     462             : 
     463           0 :         old_cred = ovl_override_creds(file_inode(file)->i_sb);
     464           0 :         ret = vfs_fallocate(real.file, mode, offset, len);
     465           0 :         revert_creds(old_cred);
     466             : 
     467             :         /* Update size */
     468           0 :         ovl_copyattr(ovl_inode_real(inode), inode);
     469             : 
     470           0 :         fdput(real);
     471             : 
     472           0 :         return ret;
     473             : }
     474             : 
     475           0 : static int ovl_fadvise(struct file *file, loff_t offset, loff_t len, int advice)
     476             : {
     477           0 :         struct fd real;
     478           0 :         const struct cred *old_cred;
     479           0 :         int ret;
     480             : 
     481           0 :         ret = ovl_real_fdget(file, &real);
     482           0 :         if (ret)
     483             :                 return ret;
     484             : 
     485           0 :         old_cred = ovl_override_creds(file_inode(file)->i_sb);
     486           0 :         ret = vfs_fadvise(real.file, offset, len, advice);
     487           0 :         revert_creds(old_cred);
     488             : 
     489           0 :         fdput(real);
     490             : 
     491           0 :         return ret;
     492             : }
     493             : 
     494           0 : static long ovl_real_ioctl(struct file *file, unsigned int cmd,
     495             :                            unsigned long arg)
     496             : {
     497           0 :         struct fd real;
     498           0 :         long ret;
     499             : 
     500           0 :         ret = ovl_real_fdget(file, &real);
     501           0 :         if (ret)
     502             :                 return ret;
     503             : 
     504           0 :         ret = security_file_ioctl(real.file, cmd, arg);
     505           0 :         if (!ret) {
     506             :                 /*
     507             :                  * Don't override creds, since we currently can't safely check
     508             :                  * permissions before doing so.
     509             :                  */
     510           0 :                 ret = vfs_ioctl(real.file, cmd, arg);
     511             :         }
     512             : 
     513           0 :         fdput(real);
     514             : 
     515           0 :         return ret;
     516             : }
     517             : 
     518           0 : static long ovl_ioctl_set_flags(struct file *file, unsigned int cmd,
     519             :                                 unsigned long arg)
     520             : {
     521           0 :         long ret;
     522           0 :         struct inode *inode = file_inode(file);
     523             : 
     524           0 :         if (!inode_owner_or_capable(&init_user_ns, inode))
     525             :                 return -EACCES;
     526             : 
     527           0 :         ret = mnt_want_write_file(file);
     528           0 :         if (ret)
     529             :                 return ret;
     530             : 
     531           0 :         inode_lock(inode);
     532             : 
     533             :         /*
     534             :          * Prevent copy up if immutable and has no CAP_LINUX_IMMUTABLE
     535             :          * capability.
     536             :          */
     537           0 :         ret = -EPERM;
     538           0 :         if (!ovl_has_upperdata(inode) && IS_IMMUTABLE(inode) &&
     539           0 :             !capable(CAP_LINUX_IMMUTABLE))
     540           0 :                 goto unlock;
     541             : 
     542           0 :         ret = ovl_maybe_copy_up(file_dentry(file), O_WRONLY);
     543           0 :         if (ret)
     544           0 :                 goto unlock;
     545             : 
     546           0 :         ret = ovl_real_ioctl(file, cmd, arg);
     547             : 
     548           0 :         ovl_copyflags(ovl_inode_real(inode), inode);
     549           0 : unlock:
     550           0 :         inode_unlock(inode);
     551             : 
     552           0 :         mnt_drop_write_file(file);
     553             : 
     554           0 :         return ret;
     555             : 
     556             : }
     557             : 
     558           0 : long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
     559             : {
     560           0 :         long ret;
     561             : 
     562           0 :         switch (cmd) {
     563           0 :         case FS_IOC_GETFLAGS:
     564             :         case FS_IOC_FSGETXATTR:
     565           0 :                 ret = ovl_real_ioctl(file, cmd, arg);
     566           0 :                 break;
     567             : 
     568           0 :         case FS_IOC_FSSETXATTR:
     569             :         case FS_IOC_SETFLAGS:
     570           0 :                 ret = ovl_ioctl_set_flags(file, cmd, arg);
     571           0 :                 break;
     572             : 
     573             :         default:
     574             :                 ret = -ENOTTY;
     575             :         }
     576             : 
     577           0 :         return ret;
     578             : }
     579             : 
     580             : #ifdef CONFIG_COMPAT
     581           0 : long ovl_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
     582             : {
     583           0 :         switch (cmd) {
     584             :         case FS_IOC32_GETFLAGS:
     585             :                 cmd = FS_IOC_GETFLAGS;
     586             :                 break;
     587             : 
     588           0 :         case FS_IOC32_SETFLAGS:
     589           0 :                 cmd = FS_IOC_SETFLAGS;
     590           0 :                 break;
     591             : 
     592             :         default:
     593             :                 return -ENOIOCTLCMD;
     594             :         }
     595             : 
     596           0 :         return ovl_ioctl(file, cmd, arg);
     597             : }
     598             : #endif
     599             : 
     600             : enum ovl_copyop {
     601             :         OVL_COPY,
     602             :         OVL_CLONE,
     603             :         OVL_DEDUPE,
     604             : };
     605             : 
     606           0 : static loff_t ovl_copyfile(struct file *file_in, loff_t pos_in,
     607             :                             struct file *file_out, loff_t pos_out,
     608             :                             loff_t len, unsigned int flags, enum ovl_copyop op)
     609             : {
     610           0 :         struct inode *inode_out = file_inode(file_out);
     611           0 :         struct fd real_in, real_out;
     612           0 :         const struct cred *old_cred;
     613           0 :         loff_t ret;
     614             : 
     615           0 :         ret = ovl_real_fdget(file_out, &real_out);
     616           0 :         if (ret)
     617             :                 return ret;
     618             : 
     619           0 :         ret = ovl_real_fdget(file_in, &real_in);
     620           0 :         if (ret) {
     621           0 :                 fdput(real_out);
     622           0 :                 return ret;
     623             :         }
     624             : 
     625           0 :         old_cred = ovl_override_creds(file_inode(file_out)->i_sb);
     626           0 :         switch (op) {
     627           0 :         case OVL_COPY:
     628           0 :                 ret = vfs_copy_file_range(real_in.file, pos_in,
     629             :                                           real_out.file, pos_out, len, flags);
     630           0 :                 break;
     631             : 
     632           0 :         case OVL_CLONE:
     633           0 :                 ret = vfs_clone_file_range(real_in.file, pos_in,
     634             :                                            real_out.file, pos_out, len, flags);
     635           0 :                 break;
     636             : 
     637           0 :         case OVL_DEDUPE:
     638           0 :                 ret = vfs_dedupe_file_range_one(real_in.file, pos_in,
     639             :                                                 real_out.file, pos_out, len,
     640             :                                                 flags);
     641           0 :                 break;
     642             :         }
     643           0 :         revert_creds(old_cred);
     644             : 
     645             :         /* Update size */
     646           0 :         ovl_copyattr(ovl_inode_real(inode_out), inode_out);
     647             : 
     648           0 :         fdput(real_in);
     649           0 :         fdput(real_out);
     650             : 
     651           0 :         return ret;
     652             : }
     653             : 
     654           0 : static ssize_t ovl_copy_file_range(struct file *file_in, loff_t pos_in,
     655             :                                    struct file *file_out, loff_t pos_out,
     656             :                                    size_t len, unsigned int flags)
     657             : {
     658           0 :         return ovl_copyfile(file_in, pos_in, file_out, pos_out, len, flags,
     659             :                             OVL_COPY);
     660             : }
     661             : 
     662           0 : static loff_t ovl_remap_file_range(struct file *file_in, loff_t pos_in,
     663             :                                    struct file *file_out, loff_t pos_out,
     664             :                                    loff_t len, unsigned int remap_flags)
     665             : {
     666           0 :         enum ovl_copyop op;
     667             : 
     668           0 :         if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY))
     669             :                 return -EINVAL;
     670             : 
     671           0 :         if (remap_flags & REMAP_FILE_DEDUP)
     672             :                 op = OVL_DEDUPE;
     673             :         else
     674             :                 op = OVL_CLONE;
     675             : 
     676             :         /*
     677             :          * Don't copy up because of a dedupe request, this wouldn't make sense
     678             :          * most of the time (data would be duplicated instead of deduplicated).
     679             :          */
     680           0 :         if (op == OVL_DEDUPE &&
     681           0 :             (!ovl_inode_upper(file_inode(file_in)) ||
     682           0 :              !ovl_inode_upper(file_inode(file_out))))
     683           0 :                 return -EPERM;
     684             : 
     685           0 :         return ovl_copyfile(file_in, pos_in, file_out, pos_out, len,
     686             :                             remap_flags, op);
     687             : }
     688             : 
     689             : const struct file_operations ovl_file_operations = {
     690             :         .open           = ovl_open,
     691             :         .release        = ovl_release,
     692             :         .llseek         = ovl_llseek,
     693             :         .read_iter      = ovl_read_iter,
     694             :         .write_iter     = ovl_write_iter,
     695             :         .fsync          = ovl_fsync,
     696             :         .mmap           = ovl_mmap,
     697             :         .fallocate      = ovl_fallocate,
     698             :         .fadvise        = ovl_fadvise,
     699             :         .unlocked_ioctl = ovl_ioctl,
     700             : #ifdef CONFIG_COMPAT
     701             :         .compat_ioctl   = ovl_compat_ioctl,
     702             : #endif
     703             :         .splice_read    = generic_file_splice_read,
     704             :         .splice_write   = iter_file_splice_write,
     705             : 
     706             :         .copy_file_range        = ovl_copy_file_range,
     707             :         .remap_file_range       = ovl_remap_file_range,
     708             : };
     709             : 
     710           1 : int __init ovl_aio_request_cache_init(void)
     711             : {
     712           1 :         ovl_aio_request_cachep = kmem_cache_create("ovl_aio_req",
     713             :                                                    sizeof(struct ovl_aio_req),
     714             :                                                    0, SLAB_HWCACHE_ALIGN, NULL);
     715           1 :         if (!ovl_aio_request_cachep)
     716           0 :                 return -ENOMEM;
     717             : 
     718             :         return 0;
     719             : }
     720             : 
     721           0 : void ovl_aio_request_cache_destroy(void)
     722             : {
     723           0 :         kmem_cache_destroy(ovl_aio_request_cachep);
     724           0 : }

Generated by: LCOV version 1.14