fuse_backend_rs/overlayfs/
sync_io.rs

1// Copyright (C) 2023 Ant Group. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use super::*;
5use std::ffi::CStr;
6use std::io::Result;
7
8use std::sync::atomic::{AtomicU64, Ordering};
9use std::sync::Arc;
10use std::time::Duration;
11
12use crate::abi::fuse_abi::{stat64, statvfs64, CreateIn};
13use crate::api::filesystem::{
14    Context, DirEntry, Entry, FileSystem, FsOptions, GetxattrReply, ListxattrReply, OpenOptions,
15    SetattrValid, ZeroCopyReader, ZeroCopyWriter,
16};
17
18use libc;
19use std::io::{Error, ErrorKind};
20
21impl FileSystem for OverlayFs {
22    type Inode = Inode;
23    type Handle = Handle;
24
25    fn init(&self, capable: FsOptions) -> Result<FsOptions> {
26        // use vfs' negotiated capability if imported
27        // other wise, do our own negotiation
28        let mut opts = FsOptions::DO_READDIRPLUS | FsOptions::READDIRPLUS_AUTO;
29
30        if self.config.do_import {
31            self.import()?;
32        }
33
34        if (!self.config.do_import || self.config.writeback)
35            && capable.contains(FsOptions::WRITEBACK_CACHE)
36        {
37            opts |= FsOptions::WRITEBACK_CACHE;
38            self.writeback.store(true, Ordering::Relaxed);
39        }
40
41        if (!self.config.do_import || self.config.no_open)
42            && capable.contains(FsOptions::ZERO_MESSAGE_OPEN)
43        {
44            opts |= FsOptions::ZERO_MESSAGE_OPEN;
45            opts.remove(FsOptions::ATOMIC_O_TRUNC);
46            self.no_open.store(true, Ordering::Relaxed);
47        }
48
49        if (!self.config.do_import || self.config.no_opendir)
50            && capable.contains(FsOptions::ZERO_MESSAGE_OPENDIR)
51        {
52            opts |= FsOptions::ZERO_MESSAGE_OPENDIR;
53            self.no_opendir.store(true, Ordering::Relaxed);
54        }
55
56        if (!self.config.do_import || self.config.killpriv_v2)
57            && capable.contains(FsOptions::HANDLE_KILLPRIV_V2)
58        {
59            opts |= FsOptions::HANDLE_KILLPRIV_V2;
60            self.killpriv_v2.store(true, Ordering::Relaxed);
61        }
62
63        if self.config.perfile_dax && capable.contains(FsOptions::PERFILE_DAX) {
64            opts |= FsOptions::PERFILE_DAX;
65            self.perfile_dax.store(true, Ordering::Relaxed);
66        }
67
68        Ok(opts)
69    }
70
71    fn destroy(&self) {}
72
73    fn statfs(&self, ctx: &Context, inode: Inode) -> Result<statvfs64> {
74        trace!("STATFS: inode: {}\n", inode);
75        self.do_statvfs(ctx, inode)
76    }
77
78    fn lookup(&self, ctx: &Context, parent: Inode, name: &CStr) -> Result<Entry> {
79        let tmp = name.to_string_lossy().to_string();
80        trace!("LOOKUP: parent: {}, name: {}\n", parent, tmp);
81        let result = self.do_lookup(ctx, parent, tmp.as_str());
82        if result.is_ok() {
83            trace!("LOOKUP result: {:?}", result.as_ref().unwrap());
84        }
85        //self.debug_print_all_inodes();
86        result
87    }
88
89    fn forget(&self, _ctx: &Context, inode: Inode, count: u64) {
90        trace!("FORGET: inode: {}, count: {}\n", inode, count);
91        self.forget_one(inode, count);
92        //self.debug_print_all_inodes();
93    }
94
95    fn batch_forget(&self, _ctx: &Context, requests: Vec<(Inode, u64)>) {
96        trace!("BATCH_FORGET: requests: {:?}\n", requests);
97        for (inode, count) in requests {
98            self.forget_one(inode, count);
99        }
100    }
101
102    fn opendir(
103        &self,
104        ctx: &Context,
105        inode: Inode,
106        _flags: u32,
107    ) -> Result<(Option<Handle>, OpenOptions)> {
108        trace!("OPENDIR: inode: {}\n", inode);
109        if self.no_opendir.load(Ordering::Relaxed) {
110            info!("fuse: opendir is not supported.");
111            return Err(Error::from_raw_os_error(libc::ENOSYS));
112        }
113
114        let mut opts = OpenOptions::empty();
115
116        if let CachePolicy::Always = self.config.cache_policy {
117            opts |= OpenOptions::KEEP_CACHE;
118        }
119
120        // lookup node
121        let node = self.lookup_node(ctx, inode, ".")?;
122
123        if node.whiteout.load(Ordering::Relaxed) {
124            return Err(Error::from_raw_os_error(libc::ENOENT));
125        }
126
127        let st = node.stat64(ctx)?;
128        if !utils::is_dir(st) {
129            return Err(Error::from_raw_os_error(libc::ENOTDIR));
130        }
131
132        let handle = self.next_handle.fetch_add(1, Ordering::Relaxed);
133
134        self.handles.lock().unwrap().insert(
135            handle,
136            Arc::new(HandleData {
137                node: Arc::clone(&node),
138                real_handle: None,
139            }),
140        );
141
142        Ok((Some(handle), opts))
143    }
144
145    fn releasedir(&self, _ctx: &Context, inode: Inode, _flags: u32, handle: Handle) -> Result<()> {
146        trace!("RELEASEDIR: inode: {}, handle: {}\n", inode, handle);
147        if self.no_opendir.load(Ordering::Relaxed) {
148            info!("fuse: releasedir is not supported.");
149            return Err(Error::from_raw_os_error(libc::ENOSYS));
150        }
151
152        self.handles.lock().unwrap().remove(&handle);
153
154        Ok(())
155    }
156
157    // for mkdir or create file
158    // 1. lookup name, if exists and not whiteout, return EEXIST
159    // 2. not exists and no whiteout, copy up parent node, ususally  a mkdir on upper layer would do the work
160    // 3. find whiteout, if whiteout in upper layer, should set opaque. if in lower layer, just mkdir?
161    fn mkdir(
162        &self,
163        ctx: &Context,
164        parent: Inode,
165        name: &CStr,
166        mode: u32,
167        umask: u32,
168    ) -> Result<Entry> {
169        let sname = name.to_string_lossy().to_string();
170
171        trace!("MKDIR: parent: {}, name: {}\n", parent, sname);
172
173        // no entry or whiteout
174        let pnode = self.lookup_node(ctx, parent, "")?;
175        if pnode.whiteout.load(Ordering::Relaxed) {
176            return Err(Error::from_raw_os_error(libc::ENOENT));
177        }
178
179        self.do_mkdir(ctx, &pnode, sname.as_str(), mode, umask)?;
180        let entry = self.do_lookup(ctx, parent, sname.as_str());
181        entry
182    }
183
184    fn rmdir(&self, ctx: &Context, parent: Inode, name: &CStr) -> Result<()> {
185        trace!(
186            "RMDIR: parent: {}, name: {}\n",
187            parent,
188            name.to_string_lossy()
189        );
190        self.do_rm(ctx, parent, name, true)
191    }
192
193    fn readdir(
194        &self,
195        ctx: &Context,
196        inode: Inode,
197        handle: Handle,
198        size: u32,
199        offset: u64,
200        add_entry: &mut dyn FnMut(DirEntry) -> Result<usize>,
201    ) -> Result<()> {
202        trace!("READDIR: inode: {}, handle: {}\n", inode, handle);
203        if self.config.no_readdir {
204            info!("fuse: readdir is not supported.");
205            return Ok(());
206        }
207        self.do_readdir(ctx, inode, handle, size, offset, false, &mut |dir_entry,
208                                                                       _|
209         -> Result<
210            usize,
211        > {
212            add_entry(dir_entry)
213        })
214    }
215
216    fn readdirplus(
217        &self,
218        ctx: &Context,
219        inode: Inode,
220        handle: Handle,
221        size: u32,
222        offset: u64,
223        add_entry: &mut dyn FnMut(DirEntry, Entry) -> Result<usize>,
224    ) -> Result<()> {
225        trace!("READDIRPLUS: inode: {}, handle: {}\n", inode, handle);
226        if self.config.no_readdir {
227            info!("fuse: readdirplus is not supported.");
228            return Ok(());
229        }
230        self.do_readdir(ctx, inode, handle, size, offset, true, &mut |dir_entry,
231                                                                      entry|
232         -> Result<
233            usize,
234        > {
235            match entry {
236                Some(e) => add_entry(dir_entry, e),
237                None => Err(Error::from_raw_os_error(libc::ENOENT)),
238            }
239        })
240    }
241
242    fn open(
243        &self,
244        ctx: &Context,
245        inode: Inode,
246        flags: u32,
247        fuse_flags: u32,
248    ) -> Result<(Option<Handle>, OpenOptions, Option<u32>)> {
249        // open assume file always exist
250        trace!("OPEN: inode: {}, flags: {}\n", inode, flags);
251        if self.no_open.load(Ordering::Relaxed) {
252            info!("fuse: open is not supported.");
253            return Err(Error::from_raw_os_error(libc::ENOSYS));
254        }
255
256        let readonly: bool = flags
257            & (libc::O_APPEND | libc::O_CREAT | libc::O_TRUNC | libc::O_RDWR | libc::O_WRONLY)
258                as u32
259            == 0;
260        // toggle flags
261        let mut flags: i32 = flags as i32;
262
263        flags |= libc::O_NOFOLLOW;
264
265        if self.config.writeback {
266            if flags & libc::O_ACCMODE == libc::O_WRONLY {
267                flags &= !libc::O_ACCMODE;
268                flags |= libc::O_RDWR;
269            }
270
271            if flags & libc::O_APPEND != 0 {
272                flags &= !libc::O_APPEND;
273            }
274        }
275        // lookup node
276        let node = self.lookup_node(ctx, inode, "")?;
277
278        // whiteout node
279        if node.whiteout.load(Ordering::Relaxed) {
280            return Err(Error::from_raw_os_error(libc::ENOENT));
281        }
282
283        if !readonly {
284            // copy up to upper layer
285            self.copy_node_up(ctx, Arc::clone(&node))?;
286        }
287
288        // assign a handle in overlayfs and open it
289        let (_l, h, _) = node.open(ctx, flags as u32, fuse_flags)?;
290        match h {
291            None => Err(Error::from_raw_os_error(libc::ENOENT)),
292            Some(handle) => {
293                let hd = self.next_handle.fetch_add(1, Ordering::Relaxed);
294                let (layer, in_upper_layer, inode) = node.first_layer_inode();
295                let handle_data = HandleData {
296                    node: Arc::clone(&node),
297                    real_handle: Some(RealHandle {
298                        layer,
299                        in_upper_layer,
300                        inode,
301                        handle: AtomicU64::new(handle),
302                    }),
303                };
304
305                self.handles
306                    .lock()
307                    .unwrap()
308                    .insert(hd, Arc::new(handle_data));
309
310                let mut opts = OpenOptions::empty();
311                match self.config.cache_policy {
312                    CachePolicy::Never => opts |= OpenOptions::DIRECT_IO,
313                    CachePolicy::Always => opts |= OpenOptions::KEEP_CACHE,
314                    _ => {}
315                }
316
317                trace!("OPEN: returning handle: {}", hd);
318
319                Ok((Some(hd), opts, None))
320            }
321        }
322    }
323
324    fn release(
325        &self,
326        ctx: &Context,
327        _inode: Inode,
328        flags: u32,
329        handle: Handle,
330        flush: bool,
331        flock_release: bool,
332        lock_owner: Option<u64>,
333    ) -> Result<()> {
334        trace!(
335            "RELEASE: inode: {}, flags: {}, handle: {}, flush: {}, flock_release: {}, lock_owner: {:?}\n",
336            _inode,
337            flags,
338            handle,
339            flush,
340            flock_release,
341            lock_owner
342        );
343
344        if self.no_open.load(Ordering::Relaxed) {
345            info!("fuse: release is not supported.");
346            return Err(Error::from_raw_os_error(libc::ENOSYS));
347        }
348
349        if let Some(hd) = self.handles.lock().unwrap().get(&handle) {
350            let rh = if let Some(ref h) = hd.real_handle {
351                h
352            } else {
353                return Err(Error::new(ErrorKind::Other, "no handle"));
354            };
355            let real_handle = rh.handle.load(Ordering::Relaxed);
356            let real_inode = rh.inode;
357            rh.layer.release(
358                ctx,
359                real_inode,
360                flags,
361                real_handle,
362                flush,
363                flock_release,
364                lock_owner,
365            )?;
366        }
367
368        self.handles.lock().unwrap().remove(&handle);
369
370        Ok(())
371    }
372
373    fn create(
374        &self,
375        ctx: &Context,
376        parent: Inode,
377        name: &CStr,
378        args: CreateIn,
379    ) -> Result<(Entry, Option<Handle>, OpenOptions, Option<u32>)> {
380        let sname = name.to_string_lossy().to_string();
381        trace!("CREATE: parent: {}, name: {}\n", parent, sname);
382
383        // Parent doesn't exist.
384        let pnode = self.lookup_node(ctx, parent, "")?;
385        if pnode.whiteout.load(Ordering::Relaxed) {
386            return Err(Error::from_raw_os_error(libc::ENOENT));
387        }
388
389        let mut hargs = args;
390        let mut flags: i32 = args.flags as i32;
391        flags |= libc::O_NOFOLLOW;
392        flags &= !libc::O_DIRECT;
393        if self.config.writeback {
394            if flags & libc::O_ACCMODE == libc::O_WRONLY {
395                flags &= !libc::O_ACCMODE;
396                flags |= libc::O_RDWR;
397            }
398
399            if flags & libc::O_APPEND != 0 {
400                flags &= !libc::O_APPEND;
401            }
402        }
403        hargs.flags = flags as u32;
404
405        let final_handle = self.do_create(ctx, &pnode, sname.as_str(), hargs)?;
406        let entry = self.do_lookup(ctx, parent, sname.as_str())?;
407
408        let mut opts = OpenOptions::empty();
409        match self.config.cache_policy {
410            CachePolicy::Never => opts |= OpenOptions::DIRECT_IO,
411            CachePolicy::Always => opts |= OpenOptions::KEEP_CACHE,
412            _ => {}
413        }
414
415        Ok((entry, final_handle, opts, None))
416    }
417
418    fn unlink(&self, ctx: &Context, parent: Inode, name: &CStr) -> Result<()> {
419        trace!(
420            "UNLINK: parent: {}, name: {}\n",
421            parent,
422            name.to_string_lossy()
423        );
424        self.do_rm(ctx, parent, name, false)
425    }
426
427    fn read(
428        &self,
429        ctx: &Context,
430        inode: Inode,
431        handle: Handle,
432        w: &mut dyn ZeroCopyWriter,
433        size: u32,
434        offset: u64,
435        lock_owner: Option<u64>,
436        flags: u32,
437    ) -> Result<usize> {
438        trace!(
439            "READ: inode: {}, handle: {}, size: {}, offset: {}, lock_owner: {:?}, flags: {}\n",
440            inode,
441            handle,
442            size,
443            offset,
444            lock_owner,
445            flags
446        );
447
448        let data = self.get_data(ctx, Some(handle), inode, flags)?;
449
450        match data.real_handle {
451            None => Err(Error::from_raw_os_error(libc::ENOENT)),
452            Some(ref hd) => hd.layer.read(
453                ctx,
454                hd.inode,
455                hd.handle.load(Ordering::Relaxed),
456                w,
457                size,
458                offset,
459                lock_owner,
460                flags,
461            ),
462        }
463    }
464
465    fn write(
466        &self,
467        ctx: &Context,
468        inode: Inode,
469        handle: Handle,
470        r: &mut dyn ZeroCopyReader,
471        size: u32,
472        offset: u64,
473        lock_owner: Option<u64>,
474        delayed_write: bool,
475        flags: u32,
476        fuse_flags: u32,
477    ) -> Result<usize> {
478        trace!(
479            "WRITE: inode: {}, handle: {}, size: {}, offset: {}, lock_owner: {:?}, delayed_write: {}, flags: {}, fuse_flags: {}\n",
480            inode,
481            handle,
482            size,
483            offset,
484            lock_owner,
485            delayed_write,
486            flags,
487            fuse_flags
488        );
489
490        let data = self.get_data(ctx, Some(handle), inode, flags)?;
491
492        match data.real_handle {
493            None => Err(Error::from_raw_os_error(libc::ENOENT)),
494            Some(ref hd) => hd.layer.write(
495                ctx,
496                hd.inode,
497                hd.handle.load(Ordering::Relaxed),
498                r,
499                size,
500                offset,
501                lock_owner,
502                delayed_write,
503                flags,
504                fuse_flags,
505            ),
506        }
507    }
508
509    fn getattr(
510        &self,
511        ctx: &Context,
512        inode: Inode,
513        handle: Option<Handle>,
514    ) -> Result<(stat64, Duration)> {
515        trace!(
516            "GETATTR: inode: {}, handle: {}\n",
517            inode,
518            handle.unwrap_or_default()
519        );
520
521        if !self.no_open.load(Ordering::Relaxed) {
522            if let Some(h) = handle {
523                if let Some(hd) = self.handles.lock().unwrap().get(&h) {
524                    if let Some(ref rh) = hd.real_handle {
525                        let (st, _d) = rh.layer.getattr(
526                            ctx,
527                            rh.inode,
528                            Some(rh.handle.load(Ordering::Relaxed)),
529                        )?;
530                        return Ok((st, self.config.attr_timeout));
531                    }
532                }
533            }
534        }
535
536        let node = self.lookup_node(ctx, inode, "")?;
537        let (layer, _, inode) = node.first_layer_inode();
538        let (st, _) = layer.getattr(ctx, inode, None)?;
539        Ok((st, self.config.attr_timeout))
540    }
541
542    fn setattr(
543        &self,
544        ctx: &Context,
545        inode: Inode,
546        attr: stat64,
547        handle: Option<Handle>,
548        valid: SetattrValid,
549    ) -> Result<(stat64, Duration)> {
550        trace!("SETATTR: inode: {}\n", inode);
551
552        // Check if upper layer exists.
553        self.upper_layer
554            .as_ref()
555            .cloned()
556            .ok_or_else(|| Error::from_raw_os_error(libc::EROFS))?;
557
558        // deal with handle first
559        if !self.no_open.load(Ordering::Relaxed) {
560            if let Some(h) = handle {
561                if let Some(hd) = self.handles.lock().unwrap().get(&h) {
562                    if let Some(ref rhd) = hd.real_handle {
563                        // handle opened in upper layer
564                        if rhd.in_upper_layer {
565                            let (st, _d) = rhd.layer.setattr(
566                                ctx,
567                                rhd.inode,
568                                attr,
569                                Some(rhd.handle.load(Ordering::Relaxed)),
570                                valid,
571                            )?;
572
573                            return Ok((st, self.config.attr_timeout));
574                        }
575                    }
576                }
577            }
578        }
579
580        let mut node = self.lookup_node(ctx, inode, "")?;
581
582        if !node.in_upper_layer() {
583            node = self.copy_node_up(ctx, Arc::clone(&node))?
584        }
585
586        let (layer, _, real_inode) = node.first_layer_inode();
587        let (st, _d) = layer.setattr(ctx, real_inode, attr, None, valid)?;
588        Ok((st, self.config.attr_timeout))
589    }
590
591    fn rename(
592        &self,
593        _ctx: &Context,
594        _olddir: Inode,
595        _odlname: &CStr,
596        _newdir: Inode,
597        _newname: &CStr,
598        _flags: u32,
599    ) -> Result<()> {
600        // complex, implement it later
601        trace!(
602            "RENAME: olddir: {}, oldname: {}, newdir: {}, newname: {}, flags: {}\n",
603            _olddir,
604            _odlname.to_string_lossy(),
605            _newdir,
606            _newname.to_string_lossy(),
607            _flags
608        );
609        Err(Error::from_raw_os_error(libc::EXDEV))
610    }
611
612    fn mknod(
613        &self,
614        ctx: &Context,
615        parent: Inode,
616        name: &CStr,
617        mode: u32,
618        rdev: u32,
619        umask: u32,
620    ) -> Result<Entry> {
621        let sname = name.to_string_lossy().to_string();
622        trace!("MKNOD: parent: {}, name: {}\n", parent, sname);
623
624        // Check if parent exists.
625        let pnode = self.lookup_node(ctx, parent, "")?;
626        if pnode.whiteout.load(Ordering::Relaxed) {
627            return Err(Error::from_raw_os_error(libc::ENOENT));
628        }
629
630        self.do_mknod(ctx, &pnode, sname.as_str(), mode, rdev, umask)?;
631        let entry = self.do_lookup(ctx, parent, sname.as_str());
632        entry
633    }
634
635    fn link(&self, ctx: &Context, inode: Inode, newparent: Inode, name: &CStr) -> Result<Entry> {
636        let sname = name.to_string_lossy().to_string();
637        trace!(
638            "LINK: inode: {}, newparent: {}, name: {}\n",
639            inode,
640            newparent,
641            sname.as_str()
642        );
643
644        let node = self.lookup_node(ctx, inode, "")?;
645        if node.whiteout.load(Ordering::Relaxed) {
646            return Err(Error::from_raw_os_error(libc::ENOENT));
647        }
648
649        let newpnode = self.lookup_node(ctx, newparent, "")?;
650        if newpnode.whiteout.load(Ordering::Relaxed) {
651            return Err(Error::from_raw_os_error(libc::ENOENT));
652        }
653
654        self.do_link(ctx, &node, &newpnode, sname.as_str())?;
655        let entry = self.do_lookup(ctx, newparent, sname.as_str());
656        entry
657    }
658
659    fn symlink(&self, ctx: &Context, linkname: &CStr, parent: Inode, name: &CStr) -> Result<Entry> {
660        // soft link
661        let sname = name.to_string_lossy().into_owned().to_owned();
662        let slinkname = linkname.to_string_lossy().into_owned().to_owned();
663        trace!(
664            "SYMLINK: linkname: {}, parent: {}, name: {}\n",
665            linkname.to_string_lossy(),
666            parent,
667            sname.as_str()
668        );
669
670        let pnode = self.lookup_node(ctx, parent, "")?;
671        self.do_symlink(ctx, slinkname.as_str(), &pnode, sname.as_str())?;
672
673        let entry = self.do_lookup(ctx, parent, sname.as_str());
674        entry
675    }
676
677    fn readlink(&self, ctx: &Context, inode: Inode) -> Result<Vec<u8>> {
678        trace!("READLINK: inode: {}\n", inode);
679
680        let node = self.lookup_node(ctx, inode, "")?;
681
682        if node.whiteout.load(Ordering::Relaxed) {
683            return Err(Error::from_raw_os_error(libc::ENOENT));
684        }
685
686        let (layer, _, inode) = node.first_layer_inode();
687        layer.readlink(ctx, inode)
688    }
689
690    fn flush(&self, ctx: &Context, inode: Inode, handle: Handle, lock_owner: u64) -> Result<()> {
691        trace!(
692            "FLUSH: inode: {}, handle: {}, lock_owner: {}\n",
693            inode,
694            handle,
695            lock_owner
696        );
697
698        if self.no_open.load(Ordering::Relaxed) {
699            return Err(Error::from_raw_os_error(libc::ENOSYS));
700        }
701
702        let node = self.lookup_node(ctx, inode, "")?;
703
704        if node.whiteout.load(Ordering::Relaxed) {
705            return Err(Error::from_raw_os_error(libc::ENOENT));
706        }
707
708        let (layer, real_inode, real_handle) = self.find_real_info_from_handle(handle)?;
709
710        // FIXME: need to test if inode matches corresponding handle?
711
712        layer.flush(ctx, real_inode, real_handle, lock_owner)
713    }
714
715    fn fsync(&self, ctx: &Context, inode: Inode, datasync: bool, handle: Handle) -> Result<()> {
716        trace!(
717            "FSYNC: inode: {}, datasync: {}, handle: {}\n",
718            inode,
719            datasync,
720            handle
721        );
722
723        self.do_fsync(ctx, inode, datasync, handle, false)
724    }
725
726    fn fsyncdir(&self, ctx: &Context, inode: Inode, datasync: bool, handle: Handle) -> Result<()> {
727        trace!(
728            "FSYNCDIR: inode: {}, datasync: {}, handle: {}\n",
729            inode,
730            datasync,
731            handle
732        );
733
734        self.do_fsync(ctx, inode, datasync, handle, true)
735    }
736
737    fn access(&self, ctx: &Context, inode: Inode, mask: u32) -> Result<()> {
738        trace!("ACCESS: inode: {}, mask: {}\n", inode, mask);
739        let node = self.lookup_node(ctx, inode, "")?;
740
741        if node.whiteout.load(Ordering::Relaxed) {
742            return Err(Error::from_raw_os_error(libc::ENOENT));
743        }
744
745        let (layer, real_inode) = self.find_real_inode(inode)?;
746        layer.access(ctx, real_inode, mask)
747    }
748
749    fn setxattr(
750        &self,
751        ctx: &Context,
752        inode: Inode,
753        name: &CStr,
754        value: &[u8],
755        flags: u32,
756    ) -> Result<()> {
757        trace!(
758            "SETXATTR: inode: {}, name: {}, value: {:?}, flags: {}\n",
759            inode,
760            name.to_string_lossy(),
761            value,
762            flags
763        );
764        let node = self.lookup_node(ctx, inode, "")?;
765
766        if node.whiteout.load(Ordering::Relaxed) {
767            return Err(Error::from_raw_os_error(libc::ENOENT));
768        }
769
770        if !node.in_upper_layer() {
771            // Copy node up.
772            self.copy_node_up(ctx, Arc::clone(&node))?;
773        }
774
775        let (layer, _, real_inode) = node.first_layer_inode();
776
777        layer.setxattr(ctx, real_inode, name, value, flags)
778
779        // TODO: recreate node since setxattr may made dir opaque. @weizhang555.zw
780    }
781
782    fn getxattr(
783        &self,
784        ctx: &Context,
785        inode: Inode,
786        name: &CStr,
787        size: u32,
788    ) -> Result<GetxattrReply> {
789        trace!(
790            "GETXATTR: inode: {}, name: {}, size: {}\n",
791            inode,
792            name.to_string_lossy(),
793            size
794        );
795        let node = self.lookup_node(ctx, inode, "")?;
796
797        if node.whiteout.load(Ordering::Relaxed) {
798            return Err(Error::from_raw_os_error(libc::ENOENT));
799        }
800
801        let (layer, real_inode) = self.find_real_inode(inode)?;
802
803        layer.getxattr(ctx, real_inode, name, size)
804    }
805
806    fn listxattr(&self, ctx: &Context, inode: Inode, size: u32) -> Result<ListxattrReply> {
807        trace!("LISTXATTR: inode: {}, size: {}\n", inode, size);
808        let node = self.lookup_node(ctx, inode, "")?;
809
810        if node.whiteout.load(Ordering::Relaxed) {
811            return Err(Error::from_raw_os_error(libc::ENOENT));
812        }
813
814        let (layer, real_inode) = self.find_real_inode(inode)?;
815
816        layer.listxattr(ctx, real_inode, size)
817    }
818
819    fn removexattr(&self, ctx: &Context, inode: Inode, name: &CStr) -> Result<()> {
820        trace!(
821            "REMOVEXATTR: inode: {}, name: {}\n",
822            inode,
823            name.to_string_lossy()
824        );
825        let node = self.lookup_node(ctx, inode, "")?;
826
827        if node.whiteout.load(Ordering::Relaxed) {
828            return Err(Error::from_raw_os_error(libc::ENOENT));
829        }
830
831        if !node.in_upper_layer() {
832            // copy node into upper layer
833            self.copy_node_up(ctx, Arc::clone(&node))?;
834        }
835
836        let (layer, _, ino) = node.first_layer_inode();
837        layer.removexattr(ctx, ino, name)
838
839        // TODO: recreate the node since removexattr may remove the opaque xattr. @weizhang555.zw
840    }
841
842    fn fallocate(
843        &self,
844        ctx: &Context,
845        inode: Inode,
846        handle: Handle,
847        mode: u32,
848        offset: u64,
849        length: u64,
850    ) -> Result<()> {
851        trace!(
852            "FALLOCATE: inode: {}, handle: {}, mode: {}, offset: {}, length: {}\n",
853            inode,
854            handle,
855            mode,
856            offset,
857            length
858        );
859        // Use O_RDONLY flags which indicates no copy up.
860        let data = self.get_data(ctx, Some(handle), inode, libc::O_RDONLY as u32)?;
861
862        match data.real_handle {
863            None => Err(Error::from_raw_os_error(libc::ENOENT)),
864            Some(ref rhd) => {
865                if !rhd.in_upper_layer {
866                    // TODO: in lower layer, error out or just success?
867                    return Err(Error::from_raw_os_error(libc::EROFS));
868                }
869                rhd.layer.fallocate(
870                    ctx,
871                    rhd.inode,
872                    rhd.handle.load(Ordering::Relaxed),
873                    mode,
874                    offset,
875                    length,
876                )
877            }
878        }
879    }
880
881    fn lseek(
882        &self,
883        ctx: &Context,
884        inode: Inode,
885        handle: Handle,
886        offset: u64,
887        whence: u32,
888    ) -> Result<u64> {
889        trace!(
890            "LSEEK: inode: {}, handle: {}, offset: {}, whence: {}\n",
891            inode,
892            handle,
893            offset,
894            whence
895        );
896        // can this be on dir? FIXME: assume file for now
897        // we need special process if it can be called on dir
898        let node = self.lookup_node(ctx, inode, "")?;
899
900        if node.whiteout.load(Ordering::Relaxed) {
901            return Err(Error::from_raw_os_error(libc::ENOENT));
902        }
903
904        let st = node.stat64(ctx)?;
905        if utils::is_dir(st) {
906            error!("lseek on directory");
907            return Err(Error::from_raw_os_error(libc::EINVAL));
908        }
909
910        let (layer, real_inode, real_handle) = self.find_real_info_from_handle(handle)?;
911        layer.lseek(ctx, real_inode, real_handle, offset, whence)
912    }
913}