fsync(1) patch to do DIOCGFLUSH on character devices

Konstantin Belousov kostikbel at gmail.com
Sun Jul 24 05:39:21 UTC 2016


On Sun, Jul 24, 2016 at 03:04:34AM +0000, Julian Hsiao wrote:
> Hi,
> 
> The fsync(1) utility is a simple wrapper around fsync(2), but I didn't find
> a similar utility for calling ioctl(DIOCGFLUSH) for character devices.
It is not similar in any reasonable interpretation of the word.

> fsync(2) is a no-op on character device files, which is a little surprising
> but makes sense I suppose (would raising EINVAL be against POSIX?).
POSIX does not mention special nodes at all, so the implementation is
free to do whatever it wants/needs.

> 
> However, conceptually the goal is the same: commit writes to permanent
> storage, so here's a small patch to fsync(1) that calls ioctl(DIOCGFLUSH)
> for character device files instead.
This ioctl() does not perform what you describe, at least not on the
level of the buffer cache/page cache for the device. It is the duty of
the filesystem (or other in-kernel consumer) to ensure that cache
is flushed when needed.

The ioctl only sends BIO_FLUSH command to the driver, which does
something to the hardware. Oftent this 'something' is either nop or have
no observable implications.

That said, I do not see the proposed change as useful.

> 
> Incidentally, turns out you need to open character device files with O_RDWR
> (or maybe O_WRONLY is enough, I didn't check) for DIOCGFLUSH, but fsync(2)
> only needs O_RDONLY for plain files. This seems a little odd; does anyone
> know why?
> 
> Julian Hsiao
> 
> Index: usr.bin/fsync/fsync.1
> ===================================================================
> diff --git a/head/usr.bin/fsync/fsync.1 b/head/usr.bin/fsync/fsync.1
> --- a/head/usr.bin/fsync/fsync.1	(revision 303213)
> +++ b/head/usr.bin/fsync/fsync.1	(working copy)
> @@ -44,6 +44,8 @@
>  .Nm
>  utility uses the
>  .Xr fsync 2
> +or the
> +.Xr ioctl 2
>  function call.
>  .Sh EXIT STATUS
>  If an error occurs, the
> Index: usr.bin/fsync/fsync.c
> ===================================================================
> diff --git a/head/usr.bin/fsync/fsync.c b/head/usr.bin/fsync/fsync.c
> --- a/head/usr.bin/fsync/fsync.c	(revision 303213)
> +++ b/head/usr.bin/fsync/fsync.c	(working copy)
> @@ -35,6 +35,10 @@
>  #include <stdlib.h>
>  #include <sysexits.h>
>  #include <unistd.h>
> +#include <string.h>
> +#include <sys/stat.h>
> +#include <sys/disk.h>
> +#include <sys/ioctl.h>
>  
>  static void	usage(void);
>  
> @@ -44,6 +48,7 @@
>  	int fd;
>  	int i;
>  	int rval;
> +	struct stat sb;
>  	
>  	if (argc < 2) {
>  		usage();
> @@ -58,11 +63,35 @@
>  				rval = EX_NOINPUT;
>  			continue;
>  		}
> +		memset(&sb, 0, sizeof(sb));
> +		if (fstat(fd, &sb) == -1) {
> +			warn("fstat %s", argv[i]);
> +			rval = EX_OSERR;
> +			continue;
> +		}
>  
> -		if (fsync(fd) == -1) {
> -			warn("fsync %s", argv[i]);
> -			if (rval == EX_OK)
> +		if (S_ISCHR(sb.st_mode)) {
> +			if (close(fd) == -1) {
> +				warn("close %s", argv[i]);
>  				rval = EX_OSERR;
> +				continue;
> +			}
> +			if ((fd = open(argv[i], O_RDWR)) == -1) {
> +				warn("open %s", argv[i]);
> +				rval = EX_NOINPUT;
> +				continue;
> +			}			
> +		
> +			if (ioctl(fd, DIOCGFLUSH) == -1) {
> +				warn("ioctl %s", argv[i]);
> +				rval = EX_OSERR;
> +			}
> +		} else {
> +			if (fsync(fd) == -1) {
> +				warn("fsync %s", argv[i]);
> +				if (rval == EX_OK)
> +					rval = EX_OSERR;
> +			}
>  		}
>  		close(fd);
>  	}
> 
> _______________________________________________
> freebsd-hackers at freebsd.org mailing list
> https://lists.freebsd.org/mailman/listinfo/freebsd-hackers
> To unsubscribe, send any mail to "freebsd-hackers-unsubscribe at freebsd.org"


More information about the freebsd-hackers mailing list