summary refs log tree commit diff
path: root/devices/src/virtio/fs/passthrough.rs
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2020-03-26 12:26:18 +0000
committerAlyssa Ross <hi@alyssa.is>2020-03-26 12:26:18 +0000
commitdbd5f925b6b2f4cb1bf87563be4d24c8ed35689a (patch)
tree5a51c0af87b6a8bb3dfe43d599cabf96523a7f6f /devices/src/virtio/fs/passthrough.rs
parent88b7821302043b7ad871fcc0c7748573d0f140e2 (diff)
parent22964eab8874d41cf0eadf03dfeb1ffb653283e5 (diff)
downloadcrosvm-dbd5f925b6b2f4cb1bf87563be4d24c8ed35689a.tar
crosvm-dbd5f925b6b2f4cb1bf87563be4d24c8ed35689a.tar.gz
crosvm-dbd5f925b6b2f4cb1bf87563be4d24c8ed35689a.tar.bz2
crosvm-dbd5f925b6b2f4cb1bf87563be4d24c8ed35689a.tar.lz
crosvm-dbd5f925b6b2f4cb1bf87563be4d24c8ed35689a.tar.xz
crosvm-dbd5f925b6b2f4cb1bf87563be4d24c8ed35689a.tar.zst
crosvm-dbd5f925b6b2f4cb1bf87563be4d24c8ed35689a.zip
Merge remote-tracking branch 'origin/master'
Diffstat (limited to 'devices/src/virtio/fs/passthrough.rs')
-rw-r--r--devices/src/virtio/fs/passthrough.rs67
1 files changed, 64 insertions, 3 deletions
diff --git a/devices/src/virtio/fs/passthrough.rs b/devices/src/virtio/fs/passthrough.rs
index bdc1c6f..419d466 100644
--- a/devices/src/virtio/fs/passthrough.rs
+++ b/devices/src/virtio/fs/passthrough.rs
@@ -395,7 +395,7 @@ impl PassthroughFs {
             libc::openat(
                 self.proc.as_raw_fd(),
                 pathname.as_ptr(),
-                (flags | libc::O_CLOEXEC) & (!libc::O_NOFOLLOW),
+                (flags | libc::O_CLOEXEC) & !(libc::O_NOFOLLOW | libc::O_DIRECT),
             )
         };
         if fd < 0 {
@@ -592,7 +592,13 @@ impl PassthroughFs {
                 OpenOptions::DIRECT_IO,
                 flags & (libc::O_DIRECTORY as u32) == 0,
             ),
-            CachePolicy::Always => opts |= OpenOptions::KEEP_CACHE,
+            CachePolicy::Always => {
+                opts |= if flags & (libc::O_DIRECTORY as u32) == 0 {
+                    OpenOptions::KEEP_CACHE
+                } else {
+                    OpenOptions::CACHE_DIR
+                }
+            }
             _ => {}
         };
 
@@ -965,7 +971,8 @@ impl FileSystem for PassthroughFs {
             libc::openat(
                 data.file.as_raw_fd(),
                 name.as_ptr(),
-                flags as i32 | libc::O_CREAT | libc::O_CLOEXEC | libc::O_NOFOLLOW,
+                (flags as i32 | libc::O_CREAT | libc::O_CLOEXEC | libc::O_NOFOLLOW)
+                    & !libc::O_DIRECT,
                 mode & !(umask & 0o777),
             )
         };
@@ -1689,4 +1696,58 @@ impl FileSystem for PassthroughFs {
             Err(io::Error::from_raw_os_error(libc::ENOTTY))
         }
     }
+
+    fn copy_file_range(
+        &self,
+        ctx: Context,
+        inode_src: Inode,
+        handle_src: Handle,
+        offset_src: u64,
+        inode_dst: Inode,
+        handle_dst: Handle,
+        offset_dst: u64,
+        length: u64,
+        flags: u64,
+    ) -> io::Result<usize> {
+        // We need to change credentials during a write so that the kernel will remove setuid or
+        // setgid bits from the file if it was written to by someone other than the owner.
+        let (_uid, _gid) = set_creds(ctx.uid, ctx.gid)?;
+        let src_data = self
+            .handles
+            .read()
+            .unwrap()
+            .get(&handle_src)
+            .filter(|hd| hd.inode == inode_src)
+            .map(Arc::clone)
+            .ok_or_else(ebadf)?;
+        let dst_data = self
+            .handles
+            .read()
+            .unwrap()
+            .get(&handle_dst)
+            .filter(|hd| hd.inode == inode_dst)
+            .map(Arc::clone)
+            .ok_or_else(ebadf)?;
+
+        let src = src_data.file.lock().as_raw_fd();
+        let dst = dst_data.file.lock().as_raw_fd();
+
+        let res = unsafe {
+            libc::syscall(
+                libc::SYS_copy_file_range,
+                src,
+                &offset_src,
+                dst,
+                offset_dst,
+                length,
+                flags,
+            )
+        };
+
+        if res >= 0 {
+            Ok(res as usize)
+        } else {
+            Err(io::Error::last_os_error())
+        }
+    }
 }