1use std::sync::Arc;
5
6use super::*;
7use crate::abi::fuse_abi::{stat64, statvfs64};
8#[cfg(any(feature = "vhost-user-fs", feature = "virtiofs"))]
9use crate::abi::virtio_fs;
10#[cfg(any(feature = "vhost-user-fs", feature = "virtiofs"))]
11use crate::transport::FsCacheReqHandler;
12
13impl FileSystem for Vfs {
14 type Inode = VfsInode;
15 type Handle = VfsHandle;
16
17 fn init(&self, opts: FsOptions) -> Result<FsOptions> {
18 if self.initialized() {
19 error!("vfs is already initialized");
20 return Err(Error::from_raw_os_error(libc::EINVAL));
21 }
22 let mut n_opts = *self.opts.load().deref().deref();
23 #[cfg(target_os = "linux")]
24 {
25 if n_opts.no_open {
26 n_opts.no_open = !(opts & FsOptions::ZERO_MESSAGE_OPEN).is_empty();
27 n_opts.out_opts.remove(FsOptions::ATOMIC_O_TRUNC);
29 } else {
30 n_opts.out_opts.remove(FsOptions::ZERO_MESSAGE_OPEN);
31 }
32 if n_opts.no_opendir {
33 n_opts.no_opendir = !(opts & FsOptions::ZERO_MESSAGE_OPENDIR).is_empty();
34 } else {
35 n_opts.out_opts.remove(FsOptions::ZERO_MESSAGE_OPENDIR);
36 }
37 if n_opts.no_writeback {
38 n_opts.out_opts.remove(FsOptions::WRITEBACK_CACHE);
39 }
40 if !n_opts.killpriv_v2 {
41 n_opts.out_opts.remove(FsOptions::HANDLE_KILLPRIV_V2);
42 }
43 }
44 n_opts.in_opts = opts;
45
46 n_opts.out_opts &= opts;
47 self.opts.store(Arc::new(n_opts));
48 {
49 let _guard = self.lock.lock().unwrap();
52 let superblocks = self.superblocks.load();
53
54 for fs in superblocks.iter().flatten() {
55 fs.init(n_opts.out_opts)?;
56 }
57 self.initialized.store(true, Ordering::Release);
58 }
59
60 Ok(n_opts.out_opts)
61 }
62
63 fn destroy(&self) {
64 if self.initialized() {
65 let superblocks = self.superblocks.load();
66
67 for fs in superblocks.iter().flatten() {
68 fs.destroy();
69 }
70
71 self.initialized.store(false, Ordering::Release);
72 }
73 }
74
75 fn lookup(&self, ctx: &Context, parent: VfsInode, name: &CStr) -> Result<Entry> {
76 if name.to_bytes_with_nul().contains(&SLASH_ASCII) {
78 return Err(io::Error::from_raw_os_error(libc::EINVAL));
79 }
80
81 match self.get_real_rootfs(parent)? {
82 (Left(fs), idata) => self.lookup_pseudo(fs, idata, ctx, name),
83 (Right(fs), idata) => {
84 let mut entry = fs.lookup(ctx, idata.ino(), name)?;
86 self.convert_entry(idata.fs_idx(), entry.inode, &mut entry)
88 }
89 }
90 }
91
92 fn forget(&self, ctx: &Context, inode: VfsInode, count: u64) {
93 match self.get_real_rootfs(inode) {
94 Ok(real_rootfs) => match real_rootfs {
95 (Left(fs), idata) => fs.forget(ctx, idata.ino(), count),
96 (Right(fs), idata) => fs.forget(ctx, idata.ino(), count),
97 },
98 Err(e) => {
99 warn!(
103 "vfs::forget: failed to get_real_rootfs {:?}, inode: {:?},
104 maybe it is possible that the vfs submount was dropped by umount,
105 which is reasonable.",
106 e, inode
107 );
108 }
109 }
110 }
111
112 fn getattr(
113 &self,
114 ctx: &Context,
115 inode: VfsInode,
116 handle: Option<VfsHandle>,
117 ) -> Result<(stat64, Duration)> {
118 match self.get_real_rootfs(inode)? {
119 (Left(fs), idata) => fs.getattr(ctx, idata.ino(), handle),
120 (Right(fs), idata) => {
121 fs.getattr(ctx, idata.ino(), handle)
122 .map(|(mut attr, duration)| {
123 attr.st_ino = idata.into();
124 self.remap_attr_id(true, &mut attr);
125 (attr, duration)
126 })
127 }
128 }
129 }
130
131 fn setattr(
132 &self,
133 ctx: &Context,
134 inode: VfsInode,
135 attr: stat64,
136 handle: Option<u64>,
137 valid: SetattrValid,
138 ) -> Result<(stat64, Duration)> {
139 match self.get_real_rootfs(inode)? {
140 (Left(fs), idata) => fs.setattr(ctx, idata.ino(), attr, handle, valid),
141 (Right(fs), idata) => {
142 let mut attr = attr;
143 self.remap_attr_id(false, &mut attr);
144 fs.setattr(ctx, idata.ino(), attr, handle, valid)
145 .map(|(mut attr, duration)| {
146 attr.st_ino = idata.into();
147 self.remap_attr_id(true, &mut attr);
148 (attr, duration)
149 })
150 }
151 }
152 }
153
154 fn readlink(&self, ctx: &Context, inode: VfsInode) -> Result<Vec<u8>> {
155 match self.get_real_rootfs(inode)? {
156 (Left(fs), idata) => fs.readlink(ctx, idata.ino()),
157 (Right(fs), idata) => fs.readlink(ctx, idata.ino()),
158 }
159 }
160
161 fn symlink(
162 &self,
163 ctx: &Context,
164 linkname: &CStr,
165 parent: VfsInode,
166 name: &CStr,
167 ) -> Result<Entry> {
168 validate_path_component(name)?;
169
170 match self.get_real_rootfs(parent)? {
171 (Left(fs), idata) => fs.symlink(ctx, linkname, idata.ino(), name),
172 (Right(fs), idata) => fs
173 .symlink(ctx, linkname, idata.ino(), name)
174 .map(|mut e| self.convert_entry(idata.fs_idx(), e.inode, &mut e))?,
175 }
176 }
177
178 fn mknod(
179 &self,
180 ctx: &Context,
181 inode: VfsInode,
182 name: &CStr,
183 mode: u32,
184 rdev: u32,
185 umask: u32,
186 ) -> Result<Entry> {
187 validate_path_component(name)?;
188
189 match self.get_real_rootfs(inode)? {
190 (Left(fs), idata) => fs.mknod(ctx, idata.ino(), name, mode, rdev, umask),
191 (Right(fs), idata) => fs
192 .mknod(ctx, idata.ino(), name, mode, rdev, umask)
193 .map(|mut e| self.convert_entry(idata.fs_idx(), e.inode, &mut e))?,
194 }
195 }
196
197 fn mkdir(
198 &self,
199 ctx: &Context,
200 parent: VfsInode,
201 name: &CStr,
202 mode: u32,
203 umask: u32,
204 ) -> Result<Entry> {
205 validate_path_component(name)?;
206
207 match self.get_real_rootfs(parent)? {
208 (Left(fs), idata) => fs.mkdir(ctx, idata.ino(), name, mode, umask),
209 (Right(fs), idata) => fs
210 .mkdir(ctx, idata.ino(), name, mode, umask)
211 .map(|mut e| self.convert_entry(idata.fs_idx(), e.inode, &mut e))?,
212 }
213 }
214
215 fn unlink(&self, ctx: &Context, parent: VfsInode, name: &CStr) -> Result<()> {
216 validate_path_component(name)?;
217
218 match self.get_real_rootfs(parent)? {
219 (Left(fs), idata) => fs.unlink(ctx, idata.ino(), name),
220 (Right(fs), idata) => fs.unlink(ctx, idata.ino(), name),
221 }
222 }
223
224 fn rmdir(&self, ctx: &Context, parent: VfsInode, name: &CStr) -> Result<()> {
225 validate_path_component(name)?;
226
227 match self.get_real_rootfs(parent)? {
228 (Left(fs), idata) => fs.rmdir(ctx, idata.ino(), name),
229 (Right(fs), idata) => fs.rmdir(ctx, idata.ino(), name),
230 }
231 }
232
233 fn rename(
234 &self,
235 ctx: &Context,
236 olddir: VfsInode,
237 oldname: &CStr,
238 newdir: VfsInode,
239 newname: &CStr,
240 flags: u32,
241 ) -> Result<()> {
242 validate_path_component(oldname)?;
243 validate_path_component(newname)?;
244
245 let (root, idata_old) = self.get_real_rootfs(olddir)?;
246 let (_, idata_new) = self.get_real_rootfs(newdir)?;
247
248 if idata_old.fs_idx() != idata_new.fs_idx() {
249 return Err(Error::from_raw_os_error(libc::EINVAL));
250 }
251
252 match root {
253 Left(fs) => fs.rename(
254 ctx,
255 idata_old.ino(),
256 oldname,
257 idata_new.ino(),
258 newname,
259 flags,
260 ),
261 Right(fs) => fs.rename(
262 ctx,
263 idata_old.ino(),
264 oldname,
265 idata_new.ino(),
266 newname,
267 flags,
268 ),
269 }
270 }
271
272 fn link(
273 &self,
274 ctx: &Context,
275 inode: VfsInode,
276 newparent: VfsInode,
277 newname: &CStr,
278 ) -> Result<Entry> {
279 validate_path_component(newname)?;
280
281 let (root, idata_old) = self.get_real_rootfs(inode)?;
282 let (_, idata_new) = self.get_real_rootfs(newparent)?;
283
284 if idata_old.fs_idx() != idata_new.fs_idx() {
285 return Err(Error::from_raw_os_error(libc::EINVAL));
286 }
287
288 match root {
289 Left(fs) => fs.link(ctx, idata_old.ino(), idata_new.ino(), newname),
290 Right(fs) => fs
291 .link(ctx, idata_old.ino(), idata_new.ino(), newname)
292 .map(|mut e| self.convert_entry(idata_new.fs_idx(), e.inode, &mut e))?,
293 }
294 }
295
296 fn open(
297 &self,
298 ctx: &Context,
299 inode: VfsInode,
300 flags: u32,
301 fuse_flags: u32,
302 ) -> Result<(Option<u64>, OpenOptions, Option<u32>)> {
303 #[cfg(target_os = "linux")]
304 if self.opts.load().no_open {
305 return Err(Error::from_raw_os_error(libc::ENOSYS));
306 }
307 match self.get_real_rootfs(inode)? {
308 (Left(fs), idata) => fs.open(ctx, idata.ino(), flags, fuse_flags),
309 (Right(fs), idata) => fs.open(ctx, idata.ino(), flags, fuse_flags),
310 }
311 }
312
313 fn create(
314 &self,
315 ctx: &Context,
316 parent: VfsInode,
317 name: &CStr,
318 args: CreateIn,
319 ) -> Result<(Entry, Option<u64>, OpenOptions, Option<u32>)> {
320 validate_path_component(name)?;
321
322 match self.get_real_rootfs(parent)? {
323 (Left(fs), idata) => fs.create(ctx, idata.ino(), name, args),
324 (Right(fs), idata) => {
325 fs.create(ctx, idata.ino(), name, args)
326 .map(|(mut a, b, c, d)| {
327 self.convert_entry(idata.fs_idx(), a.inode, &mut a)?;
328 Ok((a, b, c, d))
329 })?
330 }
331 }
332 }
333
334 fn read(
335 &self,
336 ctx: &Context,
337 inode: VfsInode,
338 handle: u64,
339 w: &mut dyn ZeroCopyWriter,
340 size: u32,
341 offset: u64,
342 lock_owner: Option<u64>,
343 flags: u32,
344 ) -> Result<usize> {
345 match self.get_real_rootfs(inode)? {
346 (Left(fs), idata) => {
347 fs.read(ctx, idata.ino(), handle, w, size, offset, lock_owner, flags)
348 }
349 (Right(fs), idata) => {
350 fs.read(ctx, idata.ino(), handle, w, size, offset, lock_owner, flags)
351 }
352 }
353 }
354
355 fn write(
356 &self,
357 ctx: &Context,
358 inode: VfsInode,
359 handle: u64,
360 r: &mut dyn ZeroCopyReader,
361 size: u32,
362 offset: u64,
363 lock_owner: Option<u64>,
364 delayed_write: bool,
365 flags: u32,
366 fuse_flags: u32,
367 ) -> Result<usize> {
368 match self.get_real_rootfs(inode)? {
369 (Left(fs), idata) => fs.write(
370 ctx,
371 idata.ino(),
372 handle,
373 r,
374 size,
375 offset,
376 lock_owner,
377 delayed_write,
378 flags,
379 fuse_flags,
380 ),
381 (Right(fs), idata) => fs.write(
382 ctx,
383 idata.ino(),
384 handle,
385 r,
386 size,
387 offset,
388 lock_owner,
389 delayed_write,
390 flags,
391 fuse_flags,
392 ),
393 }
394 }
395
396 fn flush(&self, ctx: &Context, inode: VfsInode, handle: u64, lock_owner: u64) -> Result<()> {
397 match self.get_real_rootfs(inode)? {
398 (Left(fs), idata) => fs.flush(ctx, idata.ino(), handle, lock_owner),
399 (Right(fs), idata) => fs.flush(ctx, idata.ino(), handle, lock_owner),
400 }
401 }
402
403 fn fsync(&self, ctx: &Context, inode: VfsInode, datasync: bool, handle: u64) -> Result<()> {
404 match self.get_real_rootfs(inode)? {
405 (Left(fs), idata) => fs.fsync(ctx, idata.ino(), datasync, handle),
406 (Right(fs), idata) => fs.fsync(ctx, idata.ino(), datasync, handle),
407 }
408 }
409
410 fn fallocate(
411 &self,
412 ctx: &Context,
413 inode: VfsInode,
414 handle: u64,
415 mode: u32,
416 offset: u64,
417 length: u64,
418 ) -> Result<()> {
419 match self.get_real_rootfs(inode)? {
420 (Left(fs), idata) => fs.fallocate(ctx, idata.ino(), handle, mode, offset, length),
421 (Right(fs), idata) => fs.fallocate(ctx, idata.ino(), handle, mode, offset, length),
422 }
423 }
424
425 fn release(
426 &self,
427 ctx: &Context,
428 inode: VfsInode,
429 flags: u32,
430 handle: u64,
431 flush: bool,
432 flock_release: bool,
433 lock_owner: Option<u64>,
434 ) -> Result<()> {
435 match self.get_real_rootfs(inode)? {
436 (Left(fs), idata) => fs.release(
437 ctx,
438 idata.ino(),
439 flags,
440 handle,
441 flush,
442 flock_release,
443 lock_owner,
444 ),
445 (Right(fs), idata) => fs.release(
446 ctx,
447 idata.ino(),
448 flags,
449 handle,
450 flush,
451 flock_release,
452 lock_owner,
453 ),
454 }
455 }
456
457 fn statfs(&self, ctx: &Context, inode: VfsInode) -> Result<statvfs64> {
458 match self.get_real_rootfs(inode)? {
459 (Left(fs), idata) => fs.statfs(ctx, idata.ino()),
460 (Right(fs), idata) => fs.statfs(ctx, idata.ino()),
461 }
462 }
463
464 fn setxattr(
465 &self,
466 ctx: &Context,
467 inode: VfsInode,
468 name: &CStr,
469 value: &[u8],
470 flags: u32,
471 ) -> Result<()> {
472 validate_path_component(name)?;
473
474 match self.get_real_rootfs(inode)? {
475 (Left(fs), idata) => fs.setxattr(ctx, idata.ino(), name, value, flags),
476 (Right(fs), idata) => fs.setxattr(ctx, idata.ino(), name, value, flags),
477 }
478 }
479
480 fn getxattr(
481 &self,
482 ctx: &Context,
483 inode: VfsInode,
484 name: &CStr,
485 size: u32,
486 ) -> Result<GetxattrReply> {
487 validate_path_component(name)?;
488
489 match self.get_real_rootfs(inode)? {
490 (Left(fs), idata) => fs.getxattr(ctx, idata.ino(), name, size),
491 (Right(fs), idata) => fs.getxattr(ctx, idata.ino(), name, size),
492 }
493 }
494
495 fn listxattr(&self, ctx: &Context, inode: VfsInode, size: u32) -> Result<ListxattrReply> {
496 match self.get_real_rootfs(inode)? {
497 (Left(fs), idata) => fs.listxattr(ctx, idata.ino(), size),
498 (Right(fs), idata) => fs.listxattr(ctx, idata.ino(), size),
499 }
500 }
501
502 fn removexattr(&self, ctx: &Context, inode: VfsInode, name: &CStr) -> Result<()> {
503 validate_path_component(name)?;
504
505 match self.get_real_rootfs(inode)? {
506 (Left(fs), idata) => fs.removexattr(ctx, idata.ino(), name),
507 (Right(fs), idata) => fs.removexattr(ctx, idata.ino(), name),
508 }
509 }
510
511 fn opendir(
512 &self,
513 ctx: &Context,
514 inode: VfsInode,
515 flags: u32,
516 ) -> Result<(Option<VfsHandle>, OpenOptions)> {
517 #[cfg(target_os = "linux")]
518 if self.opts.load().no_opendir {
519 return Err(Error::from_raw_os_error(libc::ENOSYS));
520 }
521 match self.get_real_rootfs(inode)? {
522 (Left(fs), idata) => fs.opendir(ctx, idata.ino(), flags),
523 (Right(fs), idata) => fs.opendir(ctx, idata.ino(), flags),
524 }
525 }
526
527 fn readdir(
528 &self,
529 ctx: &Context,
530 inode: VfsInode,
531 handle: u64,
532 size: u32,
533 offset: u64,
534 add_entry: &mut dyn FnMut(DirEntry) -> Result<usize>,
535 ) -> Result<()> {
536 match self.get_real_rootfs(inode)? {
537 (Left(fs), idata) => {
538 fs.readdir(
539 ctx,
540 idata.ino(),
541 handle,
542 size,
543 offset,
544 &mut |mut dir_entry| {
545 match self.mountpoints.load().get(&dir_entry.ino) {
546 Some(mnt) => {
548 dir_entry.ino = self.convert_inode(mnt.fs_idx, mnt.ino)?;
549 }
550 None => {
551 dir_entry.ino =
552 self.convert_inode(idata.fs_idx(), dir_entry.ino)?;
553 }
554 }
555 add_entry(dir_entry)
556 },
557 )
558 }
559
560 (Right(fs), idata) => fs.readdir(
561 ctx,
562 idata.ino(),
563 handle,
564 size,
565 offset,
566 &mut |mut dir_entry| {
567 let new_ino = self.convert_inode(idata.fs_idx(), dir_entry.ino)?;
568 dir_entry.ino = new_ino;
569 add_entry(dir_entry)
570 },
571 ),
572 }
573 }
574
575 fn readdirplus(
576 &self,
577 ctx: &Context,
578 inode: VfsInode,
579 handle: u64,
580 size: u32,
581 offset: u64,
582 add_entry: &mut dyn FnMut(DirEntry, Entry) -> Result<usize>,
583 ) -> Result<()> {
584 match self.get_real_rootfs(inode)? {
585 (Left(fs), idata) => fs.readdirplus(
586 ctx,
587 idata.ino(),
588 handle,
589 size,
590 offset,
591 &mut |mut dir_entry, mut entry| {
592 match self.mountpoints.load().get(&dir_entry.ino) {
593 Some(mnt) => {
594 dir_entry.ino = self.convert_inode(mnt.fs_idx, mnt.ino)?;
596 entry = mnt.root_entry;
597 }
598 None => {
599 dir_entry.ino = self.convert_inode(idata.fs_idx(), dir_entry.ino)?;
600 entry.inode = dir_entry.ino;
601 }
602 }
603 entry.attr.st_ino = entry.inode;
604 add_entry(dir_entry, entry)
605 },
606 ),
607
608 (Right(fs), idata) => fs.readdirplus(
609 ctx,
610 idata.ino(),
611 handle,
612 size,
613 offset,
614 &mut |mut dir_entry, mut entry| {
615 dir_entry.ino = self.convert_inode(idata.fs_idx(), entry.inode)?;
616 entry.inode = dir_entry.ino;
617 entry.attr.st_ino = entry.inode;
618 self.remap_attr_id(true, &mut entry.attr);
619 add_entry(dir_entry, entry)
620 },
621 ),
622 }
623 }
624
625 fn fsyncdir(&self, ctx: &Context, inode: VfsInode, datasync: bool, handle: u64) -> Result<()> {
626 match self.get_real_rootfs(inode)? {
627 (Left(fs), idata) => fs.fsyncdir(ctx, idata.ino(), datasync, handle),
628 (Right(fs), idata) => fs.fsyncdir(ctx, idata.ino(), datasync, handle),
629 }
630 }
631
632 fn releasedir(&self, ctx: &Context, inode: VfsInode, flags: u32, handle: u64) -> Result<()> {
633 match self.get_real_rootfs(inode)? {
634 (Left(fs), idata) => fs.releasedir(ctx, idata.ino(), flags, handle),
635 (Right(fs), idata) => fs.releasedir(ctx, idata.ino(), flags, handle),
636 }
637 }
638
639 fn access(&self, ctx: &Context, inode: VfsInode, mask: u32) -> Result<()> {
640 match self.get_real_rootfs(inode)? {
641 (Left(fs), idata) => fs.access(ctx, idata.ino(), mask),
642 (Right(fs), idata) => fs.access(ctx, idata.ino(), mask),
643 }
644 }
645
646 #[inline]
647 fn id_remap(&self, ctx: &mut Context) -> Result<()> {
648 if let Some((internal_id, external_id, range)) = self.id_mapping {
650 if ctx.uid >= external_id && ctx.uid < external_id + range {
651 ctx.uid += internal_id - external_id;
652 }
653 if ctx.gid >= external_id && ctx.gid < external_id + range {
654 ctx.gid += internal_id - external_id;
655 }
656 }
657
658 Ok(())
659 }
660
661 #[cfg(any(feature = "vhost-user-fs", feature = "virtiofs"))]
662 fn setupmapping(
663 &self,
664 ctx: &Context,
665 inode: VfsInode,
666 handle: u64,
667 foffset: u64,
668 len: u64,
669 flags: u64,
670 moffset: u64,
671 req: &mut dyn FsCacheReqHandler,
672 ) -> Result<()> {
673 match self.get_real_rootfs(inode)? {
674 (Left(fs), idata) => {
675 fs.setupmapping(ctx, idata.ino(), handle, foffset, len, flags, moffset, req)
676 }
677 (Right(fs), idata) => {
678 fs.setupmapping(ctx, idata.ino(), handle, foffset, len, flags, moffset, req)
679 }
680 }
681 }
682
683 #[cfg(any(feature = "vhost-user-fs", feature = "virtiofs"))]
684 fn removemapping(
685 &self,
686 ctx: &Context,
687 inode: VfsInode,
688 requests: Vec<virtio_fs::RemovemappingOne>,
689 req: &mut dyn FsCacheReqHandler,
690 ) -> Result<()> {
691 match self.get_real_rootfs(inode)? {
692 (Left(fs), idata) => fs.removemapping(ctx, idata.ino(), requests, req),
693 (Right(fs), idata) => fs.removemapping(ctx, idata.ino(), requests, req),
694 }
695 }
696}