Skip to content

Commit 2c99659

Browse files
committed
passthroughfs: support per-file DAX
Guest Fuse FS can enable per-file DAX by adding the "-o dax=inode" parameter at mount time. This also enable per-file of virtiofs. Whether the file enables DAX or not is determined by virtiofs. We use a relatively simple strategy to control which file enables DAX. Now the strategy is when the file is larger than a value, such as 2MB, it will enable DAX. Now this value is configured by Config.dax_file_size. * If not set dax_file_size, DAX will disable to all files. * If set dax_file_size=0, DAX will enable all files. * If set dax_file_size=N, DAX will enable only when the file size is greater than or equal to N Bytes. Signed-off-by: hugh.gxy <[email protected]>
1 parent f65851d commit 2c99659

File tree

8 files changed

+79
-4
lines changed

8 files changed

+79
-4
lines changed

src/abi/linux_abi.rs

+20
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,20 @@ const SUBMOUNTS: u32 = 0x800_0000;
182182
// Filesystem responsible for clearing security.capability xattr and setuid/setgid bits.
183183
const HANDLE_KILLPRIV_V2: u32 = 0x1000_0000;
184184

185+
// This flag indicates whether the guest kernel enable per-file dax
186+
const PERFILE_DAX: u32 = 0x4000_0000;
187+
188+
/**
189+
*
190+
* fuse_attr flags
191+
*
192+
* upstream kernel use (1 << 0) as FUSE_ATTR_SUBMOUNT,
193+
* so FUSE_ATTR_DAX will use (1 << 1)
194+
*
195+
*/
196+
/// This attribute indicates whether the file supports dax in per-file DAX mode
197+
pub const FUSE_ATTR_DAX: u32 = 1 << 1;
198+
185199
bitflags! {
186200
/// A bitfield passed in as a parameter to and returned from the `init` method of the
187201
/// `FileSystem` trait.
@@ -415,6 +429,12 @@ bitflags! {
415429
/// -. create has O_TRUNC and FOPEN_IN_KILL_SUIDGID flag set.
416430
/// -. write has WRITE_KILL_PRIV
417431
const HANDLE_KILLPRIV_V2 = HANDLE_KILLPRIV_V2;
432+
433+
/// Indicates whether the guest kernel enable per-file dax
434+
///
435+
/// If this feature is enabled, filesystem will notify guest kernel whether file
436+
/// enable DAX by EntryOut.Attr.flags of inode when lookup
437+
const PERFILE_DAX = PERFILE_DAX;
418438
}
419439
}
420440

src/api/filesystem/mod.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ pub struct Entry {
5151
/// If this value is not correct, incorrect data will be returned.
5252
pub attr: libc::stat64,
5353

54+
/// Flags for 'fuse::Attr.flags'
55+
pub attr_flags: u32,
56+
5457
/// How long the values in `attr` should be considered valid. If the attributes of the `Entry`
5558
/// are only modified by the FUSE client, then this should be set to a very large value.
5659
pub attr_timeout: Duration,
@@ -70,7 +73,7 @@ impl From<Entry> for fuse::EntryOut {
7073
attr_valid: entry.attr_timeout.as_secs(),
7174
entry_valid_nsec: entry.entry_timeout.subsec_nanos(),
7275
attr_valid_nsec: entry.attr_timeout.subsec_nanos(),
73-
attr: entry.attr.into(),
76+
attr: fuse::Attr::with_flags(entry.attr, entry.attr_flags),
7477
}
7578
}
7679
}
@@ -429,6 +432,7 @@ mod tests {
429432
inode: 1,
430433
generation: 2,
431434
attr: attr.into(),
435+
attr_flags: 0,
432436
attr_timeout: Default::default(),
433437
entry_timeout: Default::default(),
434438
};

src/api/pseudo_fs.rs

+1
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ impl<S: BitmapSlice> PseudoFs<S> {
275275
inode: ino,
276276
generation: 0,
277277
attr: attr.into(),
278+
attr_flags: 0,
278279
attr_timeout: Duration::from_secs(PSEUDOFS_DEFAULT_ATTR_TIMEOUT),
279280
entry_timeout: Duration::from_secs(PSEUDOFS_DEFAULT_ENTRY_TIMEOUT),
280281
}

src/api/server/sync_io.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -607,7 +607,8 @@ impl<F: FileSystem<S> + Sync, D: AsyncDrive, S: BitmapSlice> Server<F, D, S> {
607607
| FsOptions::ASYNC_DIO
608608
| FsOptions::HAS_IOCTL_DIR
609609
| FsOptions::MAX_PAGES
610-
| FsOptions::EXPLICIT_INVAL_DATA;
610+
| FsOptions::EXPLICIT_INVAL_DATA
611+
| FsOptions::PERFILE_DAX;
611612

612613
let capable = FsOptions::from_bits_truncate(flags);
613614

src/api/vfs/mod.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,8 @@ impl Default for VfsOptions {
214214
| FsOptions::DO_READDIRPLUS
215215
| FsOptions::READDIRPLUS_AUTO
216216
| FsOptions::ZERO_MESSAGE_OPENDIR
217-
| FsOptions::HANDLE_KILLPRIV_V2,
217+
| FsOptions::HANDLE_KILLPRIV_V2
218+
| FsOptions::PERFILE_DAX,
218219
}
219220
}
220221
}
@@ -513,6 +514,7 @@ mod tests {
513514
inode: 0,
514515
generation: 0,
515516
attr: Attr::default().into(),
517+
attr_flags: 0,
516518
attr_timeout: Duration::new(0, 0),
517519
entry_timeout: Duration::new(0, 0),
518520
})
@@ -528,6 +530,7 @@ mod tests {
528530
inode: 1,
529531
generation: 0,
530532
attr: Attr::default().into(),
533+
attr_flags: 0,
531534
attr_timeout: Duration::new(0, 0),
532535
entry_timeout: Duration::new(0, 0),
533536
})
@@ -822,6 +825,7 @@ mod tests {
822825
inode: 1,
823826
generation: 0,
824827
attr: Attr::default().into(),
828+
attr_flags: 0,
825829
attr_timeout: Duration::new(0, 0),
826830
entry_timeout: Duration::new(0, 0),
827831
},
@@ -842,6 +846,7 @@ mod tests {
842846
inode: 1,
843847
generation: 0,
844848
attr: Attr::default().into(),
849+
attr_flags: 0,
845850
attr_timeout: Duration::new(0, 0),
846851
entry_timeout: Duration::new(0, 0),
847852
},
@@ -870,7 +875,8 @@ mod tests {
870875
| FsOptions::DO_READDIRPLUS
871876
| FsOptions::READDIRPLUS_AUTO
872877
| FsOptions::ZERO_MESSAGE_OPENDIR
873-
| FsOptions::HANDLE_KILLPRIV_V2;
878+
| FsOptions::HANDLE_KILLPRIV_V2
879+
| FsOptions::PERFILE_DAX;
874880
let opts = vfs.opts.load();
875881

876882
assert_eq!(opts.no_open, true);

src/passthrough/async_io.rs

+12
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,17 @@ impl<D: AsyncDrive + Sync, S: BitmapSlice + Send + Sync> AsyncFileSystem<D, S>
314314
})
315315
.await?;
316316

317+
let mut attr_flags: u32 = 0;
318+
if let Some(dax_file_size) = self.cfg.dax_file_size {
319+
// st.stat.st_size is i64
320+
if self.perfile_dax.load(Ordering::Relaxed)
321+
&& st.stat.st_size >= 0x0
322+
&& st.stat.st_size as u64 >= dax_file_size
323+
{
324+
attr_flags |= fuse::FUSE_ATTR_DAX;
325+
}
326+
}
327+
317328
let mut found = None;
318329
'search: loop {
319330
match self.inode_map.get_alt(&ids_altkey, handle_altkey.as_ref()) {
@@ -394,6 +405,7 @@ impl<D: AsyncDrive + Sync, S: BitmapSlice + Send + Sync> AsyncFileSystem<D, S>
394405
inode,
395406
generation: 0,
396407
attr: st.get_stat(),
408+
attr_flags,
397409
attr_timeout: self.cfg.attr_timeout,
398410
entry_timeout: self.cfg.entry_timeout,
399411
})

src/passthrough/mod.rs

+26
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,13 @@ pub struct Config {
455455
/// Control whether readdir/readdirplus requests return zero dirent to client, as if the
456456
/// directory is empty even if it has children.
457457
pub no_readdir: bool,
458+
459+
/// What size file supports dax
460+
/// * If dax_file_size == None, DAX will disable to all files.
461+
/// * If dax_file_size == 0, DAX will enable all files.
462+
/// * If dax_file_size == N, DAX will enable only when the file size is greater than or equal
463+
/// to N Bytes.
464+
pub dax_file_size: Option<u64>,
458465
}
459466

460467
impl Default for Config {
@@ -472,6 +479,7 @@ impl Default for Config {
472479
killpriv_v2: false,
473480
inode_file_handles: false,
474481
no_readdir: false,
482+
dax_file_size: None,
475483
}
476484
}
477485
}
@@ -521,6 +529,10 @@ pub struct PassthroughFs<D: AsyncDrive = AsyncDriver, S: BitmapSlice + Send + Sy
521529
// Whether no_readdir is enabled.
522530
no_readdir: AtomicBool,
523531

532+
// Whether per-file DAX feature is enabled.
533+
// Init from guest kernel Init cmd of fuse fs.
534+
perfile_dax: AtomicBool,
535+
524536
cfg: Config,
525537

526538
phantom: PhantomData<D>,
@@ -554,6 +566,7 @@ impl<D: AsyncDrive, S: BitmapSlice + Send + Sync> PassthroughFs<D, S> {
554566
no_opendir: AtomicBool::new(false),
555567
killpriv_v2: AtomicBool::new(false),
556568
no_readdir: AtomicBool::new(cfg.no_readdir),
569+
perfile_dax: AtomicBool::new(false),
557570
cfg,
558571

559572
phantom: PhantomData,
@@ -756,6 +769,18 @@ impl<D: AsyncDrive, S: BitmapSlice + Send + Sync> PassthroughFs<D, S> {
756769
|fd, flags| Self::open_proc_file(&self.proc, fd, flags),
757770
)?;
758771

772+
// Whether to enable file DAX according to the value of dax_file_size
773+
let mut attr_flags: u32 = 0;
774+
if let Some(dax_file_size) = self.cfg.dax_file_size {
775+
// st.stat.st_size is i64
776+
if self.perfile_dax.load(Ordering::Relaxed)
777+
&& st.stat.st_size >= 0x0
778+
&& st.stat.st_size as u64 >= dax_file_size
779+
{
780+
attr_flags |= fuse::FUSE_ATTR_DAX;
781+
}
782+
}
783+
759784
let mut found = None;
760785
'search: loop {
761786
match self.inode_map.get_alt(&ids_altkey, handle_altkey.as_ref()) {
@@ -836,6 +861,7 @@ impl<D: AsyncDrive, S: BitmapSlice + Send + Sync> PassthroughFs<D, S> {
836861
inode,
837862
generation: 0,
838863
attr: st.get_stat(),
864+
attr_flags,
839865
attr_timeout: self.cfg.attr_timeout,
840866
entry_timeout: self.cfg.entry_timeout,
841867
})

src/passthrough/sync_io.rs

+5
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,11 @@ impl<D: AsyncDrive, S: BitmapSlice + Send + Sync> FileSystem<S> for PassthroughF
333333
self.killpriv_v2.store(true, Ordering::Relaxed);
334334
}
335335

336+
if capable.contains(FsOptions::PERFILE_DAX) {
337+
opts |= FsOptions::PERFILE_DAX;
338+
self.perfile_dax.store(true, Ordering::Relaxed);
339+
}
340+
336341
Ok(opts)
337342
}
338343

0 commit comments

Comments
 (0)