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
310 .open(ctx, idata.ino(), flags, fuse_flags)
311 .map(|(h, opt, passthrough)| (h.map(Into::into), opt, passthrough)),
312 }
313 }
314
315 fn create(
316 &self,
317 ctx: &Context,
318 parent: VfsInode,
319 name: &CStr,
320 args: CreateIn,
321 ) -> Result<(Entry, Option<u64>, OpenOptions, Option<u32>)> {
322 validate_path_component(name)?;
323
324 match self.get_real_rootfs(parent)? {
325 (Left(fs), idata) => fs.create(ctx, idata.ino(), name, args),
326 (Right(fs), idata) => {
327 fs.create(ctx, idata.ino(), name, args)
328 .map(|(mut a, b, c, d)| {
329 self.convert_entry(idata.fs_idx(), a.inode, &mut a)?;
330 Ok((a, b, c, d))
331 })?
332 }
333 }
334 }
335
336 fn read(
337 &self,
338 ctx: &Context,
339 inode: VfsInode,
340 handle: u64,
341 w: &mut dyn ZeroCopyWriter,
342 size: u32,
343 offset: u64,
344 lock_owner: Option<u64>,
345 flags: u32,
346 ) -> Result<usize> {
347 match self.get_real_rootfs(inode)? {
348 (Left(fs), idata) => {
349 fs.read(ctx, idata.ino(), handle, w, size, offset, lock_owner, flags)
350 }
351 (Right(fs), idata) => {
352 fs.read(ctx, idata.ino(), handle, w, size, offset, lock_owner, flags)
353 }
354 }
355 }
356
357 fn write(
358 &self,
359 ctx: &Context,
360 inode: VfsInode,
361 handle: u64,
362 r: &mut dyn ZeroCopyReader,
363 size: u32,
364 offset: u64,
365 lock_owner: Option<u64>,
366 delayed_write: bool,
367 flags: u32,
368 fuse_flags: u32,
369 ) -> Result<usize> {
370 match self.get_real_rootfs(inode)? {
371 (Left(fs), idata) => fs.write(
372 ctx,
373 idata.ino(),
374 handle,
375 r,
376 size,
377 offset,
378 lock_owner,
379 delayed_write,
380 flags,
381 fuse_flags,
382 ),
383 (Right(fs), idata) => fs.write(
384 ctx,
385 idata.ino(),
386 handle,
387 r,
388 size,
389 offset,
390 lock_owner,
391 delayed_write,
392 flags,
393 fuse_flags,
394 ),
395 }
396 }
397
398 fn flush(&self, ctx: &Context, inode: VfsInode, handle: u64, lock_owner: u64) -> Result<()> {
399 match self.get_real_rootfs(inode)? {
400 (Left(fs), idata) => fs.flush(ctx, idata.ino(), handle, lock_owner),
401 (Right(fs), idata) => fs.flush(ctx, idata.ino(), handle, lock_owner),
402 }
403 }
404
405 fn fsync(&self, ctx: &Context, inode: VfsInode, datasync: bool, handle: u64) -> Result<()> {
406 match self.get_real_rootfs(inode)? {
407 (Left(fs), idata) => fs.fsync(ctx, idata.ino(), datasync, handle),
408 (Right(fs), idata) => fs.fsync(ctx, idata.ino(), datasync, handle),
409 }
410 }
411
412 fn fallocate(
413 &self,
414 ctx: &Context,
415 inode: VfsInode,
416 handle: u64,
417 mode: u32,
418 offset: u64,
419 length: u64,
420 ) -> Result<()> {
421 match self.get_real_rootfs(inode)? {
422 (Left(fs), idata) => fs.fallocate(ctx, idata.ino(), handle, mode, offset, length),
423 (Right(fs), idata) => fs.fallocate(ctx, idata.ino(), handle, mode, offset, length),
424 }
425 }
426
427 fn release(
428 &self,
429 ctx: &Context,
430 inode: VfsInode,
431 flags: u32,
432 handle: u64,
433 flush: bool,
434 flock_release: bool,
435 lock_owner: Option<u64>,
436 ) -> Result<()> {
437 match self.get_real_rootfs(inode)? {
438 (Left(fs), idata) => fs.release(
439 ctx,
440 idata.ino(),
441 flags,
442 handle,
443 flush,
444 flock_release,
445 lock_owner,
446 ),
447 (Right(fs), idata) => fs.release(
448 ctx,
449 idata.ino(),
450 flags,
451 handle,
452 flush,
453 flock_release,
454 lock_owner,
455 ),
456 }
457 }
458
459 fn statfs(&self, ctx: &Context, inode: VfsInode) -> Result<statvfs64> {
460 match self.get_real_rootfs(inode)? {
461 (Left(fs), idata) => fs.statfs(ctx, idata.ino()),
462 (Right(fs), idata) => fs.statfs(ctx, idata.ino()),
463 }
464 }
465
466 fn setxattr(
467 &self,
468 ctx: &Context,
469 inode: VfsInode,
470 name: &CStr,
471 value: &[u8],
472 flags: u32,
473 ) -> Result<()> {
474 validate_path_component(name)?;
475
476 match self.get_real_rootfs(inode)? {
477 (Left(fs), idata) => fs.setxattr(ctx, idata.ino(), name, value, flags),
478 (Right(fs), idata) => fs.setxattr(ctx, idata.ino(), name, value, flags),
479 }
480 }
481
482 fn getxattr(
483 &self,
484 ctx: &Context,
485 inode: VfsInode,
486 name: &CStr,
487 size: u32,
488 ) -> Result<GetxattrReply> {
489 validate_path_component(name)?;
490
491 match self.get_real_rootfs(inode)? {
492 (Left(fs), idata) => fs.getxattr(ctx, idata.ino(), name, size),
493 (Right(fs), idata) => fs.getxattr(ctx, idata.ino(), name, size),
494 }
495 }
496
497 fn listxattr(&self, ctx: &Context, inode: VfsInode, size: u32) -> Result<ListxattrReply> {
498 match self.get_real_rootfs(inode)? {
499 (Left(fs), idata) => fs.listxattr(ctx, idata.ino(), size),
500 (Right(fs), idata) => fs.listxattr(ctx, idata.ino(), size),
501 }
502 }
503
504 fn removexattr(&self, ctx: &Context, inode: VfsInode, name: &CStr) -> Result<()> {
505 validate_path_component(name)?;
506
507 match self.get_real_rootfs(inode)? {
508 (Left(fs), idata) => fs.removexattr(ctx, idata.ino(), name),
509 (Right(fs), idata) => fs.removexattr(ctx, idata.ino(), name),
510 }
511 }
512
513 fn opendir(
514 &self,
515 ctx: &Context,
516 inode: VfsInode,
517 flags: u32,
518 ) -> Result<(Option<VfsHandle>, OpenOptions)> {
519 #[cfg(target_os = "linux")]
520 if self.opts.load().no_opendir {
521 return Err(Error::from_raw_os_error(libc::ENOSYS));
522 }
523 match self.get_real_rootfs(inode)? {
524 (Left(fs), idata) => fs.opendir(ctx, idata.ino(), flags),
525 (Right(fs), idata) => fs
526 .opendir(ctx, idata.ino(), flags)
527 .map(|(h, opt)| (h.map(Into::into), opt)),
528 }
529 }
530
531 fn readdir(
532 &self,
533 ctx: &Context,
534 inode: VfsInode,
535 handle: u64,
536 size: u32,
537 offset: u64,
538 add_entry: &mut dyn FnMut(DirEntry) -> Result<usize>,
539 ) -> Result<()> {
540 match self.get_real_rootfs(inode)? {
541 (Left(fs), idata) => {
542 fs.readdir(
543 ctx,
544 idata.ino(),
545 handle,
546 size,
547 offset,
548 &mut |mut dir_entry| {
549 match self.mountpoints.load().get(&dir_entry.ino) {
550 Some(mnt) => {
552 dir_entry.ino = self.convert_inode(mnt.fs_idx, mnt.ino)?;
553 }
554 None => {
555 dir_entry.ino =
556 self.convert_inode(idata.fs_idx(), dir_entry.ino)?;
557 }
558 }
559 add_entry(dir_entry)
560 },
561 )
562 }
563
564 (Right(fs), idata) => fs.readdir(
565 ctx,
566 idata.ino(),
567 handle,
568 size,
569 offset,
570 &mut |mut dir_entry| {
571 let new_ino = self.convert_inode(idata.fs_idx(), dir_entry.ino)?;
572 dir_entry.ino = new_ino;
573 add_entry(dir_entry)
574 },
575 ),
576 }
577 }
578
579 fn readdirplus(
580 &self,
581 ctx: &Context,
582 inode: VfsInode,
583 handle: u64,
584 size: u32,
585 offset: u64,
586 add_entry: &mut dyn FnMut(DirEntry, Entry) -> Result<usize>,
587 ) -> Result<()> {
588 match self.get_real_rootfs(inode)? {
589 (Left(fs), idata) => fs.readdirplus(
590 ctx,
591 idata.ino(),
592 handle,
593 size,
594 offset,
595 &mut |mut dir_entry, mut entry| {
596 match self.mountpoints.load().get(&dir_entry.ino) {
597 Some(mnt) => {
598 dir_entry.ino = self.convert_inode(mnt.fs_idx, mnt.ino)?;
600 entry = mnt.root_entry;
601 }
602 None => {
603 dir_entry.ino = self.convert_inode(idata.fs_idx(), dir_entry.ino)?;
604 entry.inode = dir_entry.ino;
605 }
606 }
607 entry.attr.st_ino = entry.inode;
608 add_entry(dir_entry, entry)
609 },
610 ),
611
612 (Right(fs), idata) => fs.readdirplus(
613 ctx,
614 idata.ino(),
615 handle,
616 size,
617 offset,
618 &mut |mut dir_entry, mut entry| {
619 dir_entry.ino = self.convert_inode(idata.fs_idx(), entry.inode)?;
620 entry.inode = dir_entry.ino;
621 entry.attr.st_ino = entry.inode;
622 self.remap_attr_id(true, &mut entry.attr);
623 add_entry(dir_entry, entry)
624 },
625 ),
626 }
627 }
628
629 fn fsyncdir(&self, ctx: &Context, inode: VfsInode, datasync: bool, handle: u64) -> Result<()> {
630 match self.get_real_rootfs(inode)? {
631 (Left(fs), idata) => fs.fsyncdir(ctx, idata.ino(), datasync, handle),
632 (Right(fs), idata) => fs.fsyncdir(ctx, idata.ino(), datasync, handle),
633 }
634 }
635
636 fn releasedir(&self, ctx: &Context, inode: VfsInode, flags: u32, handle: u64) -> Result<()> {
637 match self.get_real_rootfs(inode)? {
638 (Left(fs), idata) => fs.releasedir(ctx, idata.ino(), flags, handle),
639 (Right(fs), idata) => fs.releasedir(ctx, idata.ino(), flags, handle),
640 }
641 }
642
643 fn access(&self, ctx: &Context, inode: VfsInode, mask: u32) -> Result<()> {
644 match self.get_real_rootfs(inode)? {
645 (Left(fs), idata) => fs.access(ctx, idata.ino(), mask),
646 (Right(fs), idata) => fs.access(ctx, idata.ino(), mask),
647 }
648 }
649
650 #[inline]
651 fn id_remap(&self, ctx: &mut Context) -> Result<()> {
652 if let Some((internal_id, external_id, range)) = self.id_mapping {
654 if ctx.uid >= external_id && ctx.uid < external_id + range {
655 ctx.uid += internal_id - external_id;
656 }
657 if ctx.gid >= external_id && ctx.gid < external_id + range {
658 ctx.gid += internal_id - external_id;
659 }
660 }
661
662 Ok(())
663 }
664
665 #[cfg(any(feature = "vhost-user-fs", feature = "virtiofs"))]
666 fn setupmapping(
667 &self,
668 ctx: &Context,
669 inode: VfsInode,
670 handle: u64,
671 foffset: u64,
672 len: u64,
673 flags: u64,
674 moffset: u64,
675 req: &mut dyn FsCacheReqHandler,
676 ) -> Result<()> {
677 match self.get_real_rootfs(inode)? {
678 (Left(fs), idata) => {
679 fs.setupmapping(ctx, idata.ino(), handle, foffset, len, flags, moffset, req)
680 }
681 (Right(fs), idata) => {
682 fs.setupmapping(ctx, idata.ino(), handle, foffset, len, flags, moffset, req)
683 }
684 }
685 }
686
687 #[cfg(any(feature = "vhost-user-fs", feature = "virtiofs"))]
688 fn removemapping(
689 &self,
690 ctx: &Context,
691 inode: VfsInode,
692 requests: Vec<virtio_fs::RemovemappingOne>,
693 req: &mut dyn FsCacheReqHandler,
694 ) -> Result<()> {
695 match self.get_real_rootfs(inode)? {
696 (Left(fs), idata) => fs.removemapping(ctx, idata.ino(), requests, req),
697 (Right(fs), idata) => fs.removemapping(ctx, idata.ino(), requests, req),
698 }
699 }
700}