1919extern crate libc;
2020
2121use bindings:: {
22- loop_info64, LOOP_CLR_FD , LOOP_CTL_GET_FREE , LOOP_SET_CAPACITY , LOOP_SET_FD , LOOP_SET_STATUS64 ,
22+ loop_info64, LOOP_CLR_FD , LOOP_CTL_GET_FREE , LOOP_SET_CAPACITY , LOOP_SET_DIRECT_IO ,
23+ LOOP_SET_FD , LOOP_SET_STATUS64 , LO_FLAGS_AUTOCLEAR , LO_FLAGS_READ_ONLY ,
2324} ;
2425use libc:: { c_int, ioctl} ;
2526use std:: {
@@ -141,6 +142,7 @@ impl LoopDevice {
141142 AttachOptions {
142143 device : self ,
143144 info : Default :: default ( ) ,
145+ direct_io : false ,
144146 }
145147 }
146148
@@ -226,7 +228,11 @@ impl LoopDevice {
226228 . read ( true )
227229 . write ( true )
228230 . open ( backing_file) ?;
231+ self . attach_fd_with_loop_info ( bf, info)
232+ }
229233
234+ /// Attach the loop device to a fd with loop_info.
235+ fn attach_fd_with_loop_info ( & self , bf : impl AsRawFd , info : loop_info64 ) -> io:: Result < ( ) > {
230236 // Attach the file
231237 ioctl_to_error ( unsafe {
232238 ioctl (
@@ -236,18 +242,21 @@ impl LoopDevice {
236242 )
237243 } ) ?;
238244
239- if let Err ( err ) = ioctl_to_error ( unsafe {
245+ let result = unsafe {
240246 ioctl (
241247 self . device . as_raw_fd ( ) as c_int ,
242248 LOOP_SET_STATUS64 as IoctlRequest ,
243249 & info,
244250 )
245- } ) {
246- // Ignore the error to preserve the original error
247- let _ = self . detach ( ) ;
248- return Err ( err) ;
251+ } ;
252+ match ioctl_to_error ( result) {
253+ Err ( err) => {
254+ // Ignore the error to preserve the original error
255+ let _ = self . detach ( ) ;
256+ Err ( err)
257+ }
258+ Ok ( _) => Ok ( ( ) ) ,
249259 }
250- Ok ( ( ) )
251260 }
252261
253262 /// Get the path of the loop device.
@@ -314,6 +323,18 @@ impl LoopDevice {
314323 } ) ?;
315324 Ok ( ( ) )
316325 }
326+
327+ // Enable or disable direct I/O for the backing file.
328+ pub fn set_direct_io ( & self , direct_io : bool ) -> io:: Result < ( ) > {
329+ ioctl_to_error ( unsafe {
330+ ioctl (
331+ self . device . as_raw_fd ( ) as c_int ,
332+ LOOP_SET_DIRECT_IO as IoctlRequest ,
333+ if direct_io { 1 } else { 0 } ,
334+ )
335+ } ) ?;
336+ Ok ( ( ) )
337+ }
317338}
318339
319340/// Used to set options when attaching a device. Created with [LoopDevice::with()].
@@ -347,6 +368,7 @@ impl LoopDevice {
347368pub struct AttachOptions < ' d > {
348369 device : & ' d mut LoopDevice ,
349370 info : loop_info64 ,
371+ direct_io : bool ,
350372}
351373
352374impl AttachOptions < ' _ > {
@@ -362,6 +384,32 @@ impl AttachOptions<'_> {
362384 self
363385 }
364386
387+ /// Set read only flag
388+ pub fn read_only ( mut self , read_only : bool ) -> Self {
389+ if read_only {
390+ self . info . lo_flags |= LO_FLAGS_READ_ONLY ;
391+ } else {
392+ self . info . lo_flags &= !LO_FLAGS_READ_ONLY ;
393+ }
394+ self
395+ }
396+
397+ /// Set autoclear flag
398+ pub fn autoclear ( mut self , read_only : bool ) -> Self {
399+ if read_only {
400+ self . info . lo_flags |= LO_FLAGS_AUTOCLEAR ;
401+ } else {
402+ self . info . lo_flags &= !LO_FLAGS_AUTOCLEAR ;
403+ }
404+ self
405+ }
406+
407+ // Enable or disable direct I/O for the backing file.
408+ pub fn set_direct_io ( mut self , direct_io : bool ) -> Self {
409+ self . direct_io = direct_io;
410+ self
411+ }
412+
365413 /// Force the kernel to scan the partition table on a newly created loop device. Note that the
366414 /// partition table parsing depends on sector sizes. The default is sector size is 512 bytes
367415 pub fn part_scan ( mut self , enable : bool ) -> Self {
@@ -375,7 +423,21 @@ impl AttachOptions<'_> {
375423
376424 /// Attach the loop device to a file with the set options.
377425 pub fn attach ( self , backing_file : impl AsRef < Path > ) -> io:: Result < ( ) > {
378- self . device . attach_with_loop_info ( backing_file, self . info )
426+ self . device . attach_with_loop_info ( backing_file, self . info ) ?;
427+ if self . direct_io {
428+ self . device . set_direct_io ( self . direct_io ) ?;
429+ }
430+ Ok ( ( ) )
431+ }
432+
433+ /// Attach the loop device to an fd
434+ pub fn attach_fd ( self , backing_file_fd : impl AsRawFd ) -> io:: Result < ( ) > {
435+ self . device
436+ . attach_fd_with_loop_info ( backing_file_fd, self . info ) ?;
437+ if self . direct_io {
438+ self . device . set_direct_io ( self . direct_io ) ?;
439+ }
440+ Ok ( ( ) )
379441 }
380442}
381443
0 commit comments