Discussion:
[ast-developers] Patch to add support for |fsync()| and |syncfs()| to sync(1) ...
Roland Mainz
2013-07-04 13:17:00 UTC
Permalink
Hi!

----

Attached (as "astksh20130628_sync_fsync_syncfs001.diff.txt") is a
patch which adds support for |fsync()| and |syncfs()| to the sync(1)
builtin.

The main purpose of the patch is to help in three cases:
1. Networked/distributed filesystems where |fsync()| or |syncfs()| can
used to force syncronisation with the server (for example usefull to
weed-out NFSv4 delegation bugs or for syncronisation primitives)
2. Operating system install software (which may not use a graceful
shutdown before reboot)
3. Logout scripts (e.g. call |syncfs()| for a user's home directory at
logout time to flush his/her data to storage and make (memory) buffer
space available for something else. This (much more fine-grained
approach) may be preferred over a "raw" sync(2) call on multiuser
systems with hundreds of users)

Question (mainly for Glenn):
Do you see any need that we have to call SFIO's flush facilities
before calling |fsync()| or |syncfs()| ?

Comments/rants/etc. welcome...

----

Bye,
Roland
--
__ . . __
(o.\ \/ /.o) roland.mainz at nrubsig.org
\__\/\/__/ MPEG specialist, C&&JAVA&&Sun&&Unix programmer
/O /==\ O\ TEL +49 641 3992797
(;O/ \/ \O;)
-------------- next part --------------
diff -N -r -u build_i386_64bit_debug/src/lib/libcmd/features/fssync build_i386_64bit_syncfs/src/lib/libcmd/features/fssync
--- build_i386_64bit_debug/src/lib/libcmd/features/fssync 1970-01-01 01:00:00.000000000 +0100
+++ build_i386_64bit_syncfs/src/lib/libcmd/features/fssync 2013-07-04 14:13:19.645395128 +0200
@@ -0,0 +1 @@
+lib fsync,syncfs,sync
diff -N -r -u build_i386_64bit_debug/src/lib/libcmd/Mamfile build_i386_64bit_syncfs/src/lib/libcmd/Mamfile
--- build_i386_64bit_debug/src/lib/libcmd/Mamfile 2013-06-28 09:02:54.000000000 +0200
+++ build_i386_64bit_syncfs/src/lib/libcmd/Mamfile 2013-07-04 14:11:41.784319015 +0200
@@ -403,7 +403,13 @@
prev cmd.h implicit
done sum.c
make sync.c
-prev ${PACKAGE_ast_INCLUDE}/ls.h implicit
+make FEATURE/fssync implicit
+meta FEATURE/fssync features/%>FEATURE/% features/fssync fssync
+make features/fssync
+done features/fssync
+exec - iffe -v -c '${CC} ${mam_cc_FLAGS} ${CCFLAGS} ${LDFLAGS} ' ref ${mam_cc_L+-L${INSTALLROOT}/lib} -I${PACKAGE_ast_INCLUDE} -I${INSTALLROOT}/include ${mam_libutil} ${mam_libast} : run features/fssync
+done FEATURE/fssync generated
+prev ${PACKAGE_ast_INCLUDE}/proc.h implicit
prev cmd.h implicit
done sync.c
make tail.c
diff -N -r -u build_i386_64bit_debug/src/lib/libcmd/sync.c build_i386_64bit_syncfs/src/lib/libcmd/sync.c
--- build_i386_64bit_debug/src/lib/libcmd/sync.c 2012-01-10 19:56:27.000000000 +0100
+++ build_i386_64bit_syncfs/src/lib/libcmd/sync.c 2013-07-04 14:55:35.944339714 +0200
@@ -25,39 +25,89 @@
* AT&T Research
*/

+#include <cmd.h>
+#include <ls.h>
+#include "FEATURE/fssync"
+
static const char usage[] =
-"[-?\n@(#)$Id: sync (AT&T Research) 2006-10-04 $\n]"
-USAGE_LICENSE
+"[-?\n@(#)$Id: sync (AT&T Research) 2013-04-24 $\n]"
"[+NAME?sync - schedule file system updates]"
-"[+DESCRIPTION?\bsync\b calls \bsync\b(2), which causes all information "
- "in memory that updates file systems to be scheduled for writing out to "
- "all file systems. The writing, although scheduled, is not necessarily "
- "complete upon return from \bsync\b.]"
-"[+?Since \bsync\b(2) has no failure indication, \bsync\b only fails for "
- "option/operand syntax errors, or when \bsync\b(2) does not return, in "
- "which case \bsync\b also does not return.]"
-"[+?At minimum \bsync\b should be called before halting the system. Most "
- "systems provide graceful shutdown procedures that include \bsync\b -- "
- "use them if possible.]"
+"[+DESCRIPTION?\bsync\b issues either the transfer of all data to storage "
+ "for an individual file descriptor, the associated filesystem for "
+ "a file descriptor or all file data in the whole system.]"
+/* -f is reserved for |fflush()| - if we ever want to implement it */
+#ifdef _lib_fsync
+"[s:fsync]:[fd?All data for the open file descriptor is to be transferred "
+ "to the storage device associated with the file described by "
+ "fildes via calling \bfsync\b(2). The utility will not return "
+ "until the system has completed that action or until an error "
+ "is detected.]"
+#endif
+#ifdef _lib_syncfs
+"[S:syncfs]:[fd?Synchronizes just the file system containing file referred to "
+ "by the open file descriptor fd by calling \bsyncfs\b(2).]"
+#endif
+#ifdef _lib_sync
+"[X:sync?Causes all information in memory that updates file systems to be "
+ "scheduled for writing out to all file systems by calling "
+ "\bsync\b(2). The writing, although scheduled, is not necessarily "
+ "complete upon return from \bsync\b. "
+ "Since \bsync\b(2) has no failure indication, \bsync\b only fails for "
+ "option/operand syntax errors, or when \bsync\b(2) does not return, in "
+ "which case \bsync\b also does not return.]"
+#endif
+"[+Option \b-X\b is implied if no other option is given.]"
+
+"[+?At minimum \bsync\b (without options) should be called before halting "
+ "the system. Most systems provide graceful shutdown procedures that "
+ "include \bsync\b -- use them if possible.]"
+
"[+EXIT STATUS?]"
"{"
- "[+0?\bsync\b(2) returned.]"
+ "[+0?Operation succeeded.]"
"[+>0?Option/operand syntax error.]"
"}"
-"[+SEE ALSO?\bsync\b(2), \bshutdown\b(8)]"
+"[+SEE ALSO?\bsync\b(2), \bfsync\b(2), \bsyncfs\b(2), \bshutdown\b(8)]"
;

-#include <cmd.h>
-#include <ls.h>

int
b_sync(int argc, char** argv, Shbltin_t* context)
{
- cmdinit(argc, argv, context, ERROR_CATALOG, 0);
+#ifdef _lib_fsync
+ int fsync_fd = -1;
+#endif
+#ifdef _lib_syncfs
+ int syncfs_fd = -1;
+#endif
+ bool do_sync = false;
+ bool failure = false;
+
for (;;)
{
switch (optget(argv, usage))
{
+#ifdef _lib_fsync
+ case 's':
+ errno = 0;
+ fsync_fd = strtol(opt_info.arg, (char **)NULL, 0);
+ if (errno != 0 || fsync_fd < 0)
+ error(ERROR_system(1), "%s: invalid file descriptor", opt_info.arg);
+ break;
+#endif
+#ifdef _lib_syncfs
+ case 'S':
+ errno = 0;
+ syncfs_fd = strtol(opt_info.arg, (char **)NULL, 0);
+ if (errno != 0 || syncfs_fd < 0)
+ error(ERROR_system(1), "%s: invalid file descriptor", opt_info.arg);
+ break;
+#endif
+#ifdef _lib_sync
+ case 'X':
+ do_sync=true;
+ break;
+#endif
case ':':
error(2, "%s", opt_info.arg);
break;
@@ -70,10 +120,43 @@
argv += opt_info.index;
if (error_info.errors || *argv)
error(ERROR_usage(2), "%s", optusage(NiL));
+
+ if (
+#ifdef _lib_fsync
+ fsync_fd == -1 &&
+#endif
+#ifdef _lib_syncfs
+ syncfs_fd == -1 &&
+#endif
+ true)
+ do_sync=true;
+
+#ifdef _lib_fsync
+ if (fsync_fd >=0)
+ {
+ if (fsync(fsync_fd) < 0)
+ {
+ error(ERROR_system(0), "fsync(%d) failed", fsync_fd);
+ failure=true;
+ }
+ }
+#endif
+#ifdef _lib_syncfs
+ if (syncfs_fd >=0)
+ {
+ if (syncfs(syncfs_fd) < 0)
+ {
+ error(ERROR_system(0), "syncfs(%d) failed", syncfs_fd);
+ failure=true;
+ }
+ }
+#endif
+ if (do_sync)
#if _lib_sync
- sync();
+ sync();
#else
- error(ERROR_usage(2), "failed -- the native system does not provide a sync(2) call");
+ error(ERROR_usage(2), "failed -- the native system does not provide a sync(2) call");
#endif
- return 0;
+
+ return failure?1:0;
}
Irek Szczesniak
2013-07-15 07:10:10 UTC
Permalink
Post by Roland Mainz
Hi!
----
Attached (as "astksh20130628_sync_fsync_syncfs001.diff.txt") is a
patch which adds support for |fsync()| and |syncfs()| to the sync(1)
builtin.
1. Networked/distributed filesystems where |fsync()| or |syncfs()| can
used to force syncronisation with the server (for example usefull to
weed-out NFSv4 delegation bugs or for syncronisation primitives)
2. Operating system install software (which may not use a graceful
shutdown before reboot)
3. Logout scripts (e.g. call |syncfs()| for a user's home directory at
logout time to flush his/her data to storage and make (memory) buffer
space available for something else. This (much more fine-grained
approach) may be preferred over a "raw" sync(2) call on multiuser
systems with hundreds of users)
Do you see any need that we have to call SFIO's flush facilities
before calling |fsync()| or |syncfs()| ?
IMO you have to do that to ensure that nothing is left in sfio's
buffers. Remember the rule: First flush to get a safe state, and then
sync to disk.
Post by Roland Mainz
Comments/rants/etc. welcome...
Irek
Glenn Fowler
2013-07-16 15:04:00 UTC
Permalink
Post by Irek Szczesniak
Post by Roland Mainz
Hi!
----
Attached (as "astksh20130628_sync_fsync_syncfs001.diff.txt") is a
patch which adds support for |fsync()| and |syncfs()| to the sync(1)
builtin.
1. Networked/distributed filesystems where |fsync()| or |syncfs()| can
used to force syncronisation with the server (for example usefull to
weed-out NFSv4 delegation bugs or for syncronisation primitives)
2. Operating system install software (which may not use a graceful
shutdown before reboot)
3. Logout scripts (e.g. call |syncfs()| for a user's home directory at
logout time to flush his/her data to storage and make (memory) buffer
space available for something else. This (much more fine-grained
approach) may be preferred over a "raw" sync(2) call on multiuser
systems with hundreds of users)
Do you see any need that we have to call SFIO's flush facilities
before calling |fsync()| or |syncfs()| ?
IMO you have to do that to ensure that nothing is left in sfio's
buffers. Remember the rule: First flush to get a safe state, and then
sync to disk.
sfsync(NiL) should be called
Roland Mainz
2013-07-27 10:03:39 UTC
Permalink
Post by Glenn Fowler
Post by Irek Szczesniak
Post by Roland Mainz
Attached (as "astksh20130628_sync_fsync_syncfs001.diff.txt") is a
patch which adds support for |fsync()| and |syncfs()| to the sync(1)
builtin.
1. Networked/distributed filesystems where |fsync()| or |syncfs()| can
used to force syncronisation with the server (for example usefull to
weed-out NFSv4 delegation bugs or for syncronisation primitives)
2. Operating system install software (which may not use a graceful
shutdown before reboot)
3. Logout scripts (e.g. call |syncfs()| for a user's home directory at
logout time to flush his/her data to storage and make (memory) buffer
space available for something else. This (much more fine-grained
approach) may be preferred over a "raw" sync(2) call on multiuser
systems with hundreds of users)
Do you see any need that we have to call SFIO's flush facilities
before calling |fsync()| or |syncfs()| ?
IMO you have to do that to ensure that nothing is left in sfio's
buffers. Remember the rule: First flush to get a safe state, and then
sync to disk.
sfsync(NiL) should be called
Just to make sure: This only flushes data which should be written to a
file and not flush input streams, right ?

Attached (as "astksh20130719_sync_fsync_syncfs002.diff.txt") is an
updated patch which fixes the issues and some other things...
including "clang" cleanup etc.) ...

----

Bye,
Roland
--
__ . . __
(o.\ \/ /.o) roland.mainz at nrubsig.org
\__\/\/__/ MPEG specialist, C&&JAVA&&Sun&&Unix programmer
/O /==\ O\ TEL +49 641 3992797
(;O/ \/ \O;)
-------------- next part --------------
diff -N -r -u build_i386_64bit_debug/src/lib/libcmd/features/fssync build_sync/src/lib/libcmd/features/fssync
--- src/lib/libcmd/features/fssync 1970-01-01 01:00:00.000000000 +0100
+++ src/lib/libcmd/features/fssync 2013-07-27 10:42:32.274180762 +0200
@@ -0,0 +1 @@
+lib fsync,syncfs,sync
diff -N -r -u build_i386_64bit_debug/src/lib/libcmd/Mamfile build_sync/src/lib/libcmd/Mamfile
--- src/lib/libcmd/Mamfile 2013-07-20 03:17:30.000000000 +0200
+++ src/lib/libcmd/Mamfile 2013-07-27 10:42:32.276180810 +0200
@@ -403,7 +403,13 @@
prev cmd.h implicit
done sum.c
make sync.c
-prev ${PACKAGE_ast_INCLUDE}/ls.h implicit
+make FEATURE/fssync implicit
+meta FEATURE/fssync features/%>FEATURE/% features/fssync fssync
+make features/fssync
+done features/fssync
+exec - iffe -v -c '${CC} ${mam_cc_FLAGS} ${CCFLAGS} ${LDFLAGS} ' ref ${mam_cc_L+-L${INSTALLROOT}/lib} -I${PACKAGE_ast_INCLUDE} -I${INSTALLROOT}/include ${mam_libutil} ${mam_libast} : run features/fssync
+done FEATURE/fssync generated
+prev ${PACKAGE_ast_INCLUDE}/proc.h implicit
prev cmd.h implicit
done sync.c
make tail.c
diff -N -r -u build_i386_64bit_debug/src/lib/libcmd/sync.c build_sync/src/lib/libcmd/sync.c
--- src/lib/libcmd/sync.c 2012-01-10 19:56:27.000000000 +0100
+++ src/lib/libcmd/sync.c 2013-07-27 11:32:56.532750698 +0200
@@ -25,39 +25,93 @@
* AT&T Research
*/

-static const char usage[] =
-"[-?\n@(#)$Id: sync (AT&T Research) 2006-10-04 $\n]"
-USAGE_LICENSE
-"[+NAME?sync - schedule file system updates]"
-"[+DESCRIPTION?\bsync\b calls \bsync\b(2), which causes all information "
- "in memory that updates file systems to be scheduled for writing out to "
- "all file systems. The writing, although scheduled, is not necessarily "
- "complete upon return from \bsync\b.]"
-"[+?Since \bsync\b(2) has no failure indication, \bsync\b only fails for "
- "option/operand syntax errors, or when \bsync\b(2) does not return, in "
- "which case \bsync\b also does not return.]"
-"[+?At minimum \bsync\b should be called before halting the system. Most "
- "systems provide graceful shutdown procedures that include \bsync\b -- "
- "use them if possible.]"
+#include <cmd.h>
+#include <ls.h>
+#include "FEATURE/fssync"
+
+static const char optsync[] =
+"[-?\n@(#)$Id: sync (AT&T Research) 2013-07-26 $\n]"
+"[-author?Roland Mainz <roland.mainz at nrubsig.org>]"
+"[+NAME?sync - schedule file/file system updates]"
+"[+DESCRIPTION?\bsync\b(1) issues either the transfer of all data to "
+ "storage for an individual file descriptor, the associated "
+ "filesystem for a file descriptor or all file data in the "
+ "whole system.]"
+/* -f is reserved for |fflush()| - if we ever want to implement it */
+#ifdef _lib_fsync
+"[s:fsync]:[fd?All data for the open file descriptor is to be transferred "
+ "to the storage device associated with the file described by "
+ "fildes via calling \bfsync\b(2). The utility will not return "
+ "until the system has completed that action or until an error "
+ "is detected.]"
+#endif
+#ifdef _lib_syncfs
+"[S:syncfs]:[fd?Synchronizes just the file system containing file referred to "
+ "by the open file descriptor fd by calling \bsyncfs\b(2).]"
+#endif
+#ifdef _lib_sync
+"[X:sync?Causes all information in memory that updates file systems to be "
+ "scheduled for writing out to all file systems by calling "
+ "\bsync\b(2). The writing, although scheduled, is not necessarily "
+ "complete upon return from \bsync\b. "
+ "Since \bsync\b(2) has no failure indication, \bsync\b only fails for "
+ "option/operand syntax errors, or when \bsync\b(2) does not return, in "
+ "which case \bsync\b(1) also does not return.]"
+#endif
+"[+?Option \b-X\b is implied if no other option is given.]"
+
+"[+?At minimum \bsync\b (without options) should be called before halting "
+ "the system. Most systems provide graceful shutdown procedures that "
+ "include \bsync\b -- use them if possible.]"
+
"[+EXIT STATUS?]"
"{"
- "[+0?\bsync\b(2) returned.]"
+ "[+0?Operation succeeded.]"
"[+>0?Option/operand syntax error.]"
"}"
-"[+SEE ALSO?\bsync\b(2), \bshutdown\b(8)]"
+"[+SEE ALSO?\bsync\b(2), \bfsync\b(2), \bsyncfs\b(2), \bshutdown\b(8)]"
;

-#include <cmd.h>
-#include <ls.h>

int
b_sync(int argc, char** argv, Shbltin_t* context)
{
- cmdinit(argc, argv, context, ERROR_CATALOG, 0);
+ NOT_USED(context);
+#ifdef _lib_fsync
+ int fsync_fd = -1;
+#endif
+#ifdef _lib_syncfs
+ int syncfs_fd = -1;
+#endif
+ bool do_sync = false;
+ bool failure = false;
+
for (;;)
{
- switch (optget(argv, usage))
+ switch (optget(argv, optsync))
{
+ /* -f is reserved for |fflush()| - if we ever want to implement it */
+#ifdef _lib_fsync
+ case 's':
+ errno = 0;
+ fsync_fd = strtol(opt_info.arg, (char **)NULL, 0);
+ if ((errno != 0) || (fsync_fd < 0))
+ error(ERROR_system(1), "%s: invalid file descriptor", opt_info.arg);
+ break;
+#endif
+#ifdef _lib_syncfs
+ case 'S':
+ errno = 0;
+ syncfs_fd = strtol(opt_info.arg, (char **)NULL, 0);
+ if ((errno != 0) || (syncfs_fd < 0))
+ error(ERROR_system(1), "%s: invalid file descriptor", opt_info.arg);
+ break;
+#endif
+#ifdef _lib_sync
+ case 'X':
+ do_sync=true;
+ break;
+#endif
case ':':
error(2, "%s", opt_info.arg);
break;
@@ -70,10 +124,69 @@
argv += opt_info.index;
if (error_info.errors || *argv)
error(ERROR_usage(2), "%s", optusage(NiL));
+
+ if (
+#ifdef _lib_fsync
+ (fsync_fd == -1) &&
+#endif
+#ifdef _lib_syncfs
+ (syncfs_fd == -1) &&
+#endif
+ true)
+ do_sync = true;
+
+#ifdef _lib_fsync
+ if (fsync_fd >= 0)
+ {
+ if (fsync(fsync_fd) < 0)
+ {
+ error(ERROR_system(0), "fsync(%d) failed", fsync_fd);
+ failure = true;
+ }
+ }
+#endif
+
+ if (
+#ifdef _lib_syncfs
+ (syncfs_fd >= 0) ||
+#endif
+ do_sync)
+ {
+ /*
+ * sync all streams. We do this for two reasons:
+ * 1. All data we buffer internally are flushed first
+ * to prevent that something important gets lost if
+ * the machine looses power immediately after the
+ * sync(1) call
+ * 2. Sometimes sync(1) is used to reach a "stable
+ * state on disk". We can't meet this expectation if
+ * we keep data buffered internally, call the sync(1)
+ * builtin and then ruin the stable state by
+ * immediately afterwards flushing some bits of data
+ * to the filesystem buffers to make the state on
+ * disk "stale" again.
+ */
+ sfsync(NiL);
+ }
+
+#ifdef _lib_syncfs
+ if (syncfs_fd >= 0)
+ {
+ if (syncfs(syncfs_fd) < 0)
+ {
+ error(ERROR_system(0), "syncfs(%d) failed", syncfs_fd);
+ failure = true;
+ }
+ }
+#endif
+ if (do_sync)
+ {
#if _lib_sync
- sync();
+ sync();
#else
- error(ERROR_usage(2), "failed -- the native system does not provide a sync(2) call");
+ error(ERROR_usage(2), "failed -- the native system does not provide a sync(2) call");
#endif
- return 0;
+ }
+
+ return failure?1:0;
}
Roland Mainz
2013-07-29 12:31:29 UTC
Permalink
Post by Roland Mainz
Post by Glenn Fowler
Post by Irek Szczesniak
Post by Roland Mainz
Attached (as "astksh20130628_sync_fsync_syncfs001.diff.txt") is a
patch which adds support for |fsync()| and |syncfs()| to the sync(1)
builtin.
1. Networked/distributed filesystems where |fsync()| or |syncfs()| can
used to force syncronisation with the server (for example usefull to
weed-out NFSv4 delegation bugs or for syncronisation primitives)
2. Operating system install software (which may not use a graceful
shutdown before reboot)
3. Logout scripts (e.g. call |syncfs()| for a user's home directory at
logout time to flush his/her data to storage and make (memory) buffer
space available for something else. This (much more fine-grained
approach) may be preferred over a "raw" sync(2) call on multiuser
systems with hundreds of users)
Do you see any need that we have to call SFIO's flush facilities
before calling |fsync()| or |syncfs()| ?
IMO you have to do that to ensure that nothing is left in sfio's
buffers. Remember the rule: First flush to get a safe state, and then
sync to disk.
sfsync(NiL) should be called
Just to make sure: This only flushes data which should be written to a
file and not flush input streams, right ?
Attached (as "astksh20130719_sync_fsync_syncfs002.diff.txt") is an
updated patch which fixes the issues and some other things...
including "clang" cleanup etc.) ...
Attached (as "astksh20130727_sync_fsync_syncfs003.diff.txt") is an
updated patch which addresses all issues which came up during code
review...

... Glenn: Can we stuff this into the next alpha too, please (should
be pretty safe because the changes are isolated and guarded by iffe
probes) ?

----

Bye,
Roland
--
__ . . __
(o.\ \/ /.o) roland.mainz at nrubsig.org
\__\/\/__/ MPEG specialist, C&&JAVA&&Sun&&Unix programmer
/O /==\ O\ TEL +49 641 3992797
(;O/ \/ \O;)
-------------- next part --------------
diff -N -r -u build_i386_64bit_debug/src/lib/libcmd/features/fssync build_sync/src/lib/libcmd/features/fssync
--- src/lib/libcmd/features/fssync 1970-01-01 01:00:00.000000000 +0100
+++ src/lib/libcmd/features/fssync 2013-07-29 14:03:29.840076545 +0200
@@ -0,0 +1 @@
+lib fsync,syncfs,sync
diff -N -r -u build_i386_64bit_debug/src/lib/libcmd/Mamfile build_sync/src/lib/libcmd/Mamfile
--- src/lib/libcmd/Mamfile 2013-07-27 17:46:53.000000000 +0200
+++ src/lib/libcmd/Mamfile 2013-07-29 14:03:29.843076715 +0200
@@ -408,7 +408,13 @@
prev cmd.h implicit
done sum.c
make sync.c
-prev ${PACKAGE_ast_INCLUDE}/ls.h implicit
+make FEATURE/fssync implicit
+meta FEATURE/fssync features/%>FEATURE/% features/fssync fssync
+make features/fssync
+done features/fssync
+exec - iffe -v -c '${CC} ${mam_cc_FLAGS} ${CCFLAGS} ${LDFLAGS} ' ref ${mam_cc_L+-L${INSTALLROOT}/lib} -I${PACKAGE_ast_INCLUDE} -I${INSTALLROOT}/include ${mam_libutil} ${mam_libast} : run features/fssync
+done FEATURE/fssync generated
+prev ${PACKAGE_ast_INCLUDE}/proc.h implicit
prev cmd.h implicit
done sync.c
make tail.c
diff -N -r -u build_i386_64bit_debug/src/lib/libcmd/sync.c build_sync/src/lib/libcmd/sync.c
--- src/lib/libcmd/sync.c 2012-01-10 19:56:27.000000000 +0100
+++ src/lib/libcmd/sync.c 2013-07-29 14:18:46.443319743 +0200
@@ -20,44 +20,85 @@
***********************************************************************/
#pragma prototyped
/*
- * David Korn
- * Glenn Fowler
+ * Roland Mainz
* AT&T Research
*/

-static const char usage[] =
-"[-?\n@(#)$Id: sync (AT&T Research) 2006-10-04 $\n]"
-USAGE_LICENSE
-"[+NAME?sync - schedule file system updates]"
-"[+DESCRIPTION?\bsync\b calls \bsync\b(2), which causes all information "
- "in memory that updates file systems to be scheduled for writing out to "
- "all file systems. The writing, although scheduled, is not necessarily "
- "complete upon return from \bsync\b.]"
-"[+?Since \bsync\b(2) has no failure indication, \bsync\b only fails for "
- "option/operand syntax errors, or when \bsync\b(2) does not return, in "
- "which case \bsync\b also does not return.]"
-"[+?At minimum \bsync\b should be called before halting the system. Most "
- "systems provide graceful shutdown procedures that include \bsync\b -- "
- "use them if possible.]"
-"[+EXIT STATUS?]"
- "{"
- "[+0?\bsync\b(2) returned.]"
- "[+>0?Option/operand syntax error.]"
- "}"
-"[+SEE ALSO?\bsync\b(2), \bshutdown\b(8)]"
-;
-
#include <cmd.h>
#include <ls.h>
+#include "FEATURE/fssync"
+
+static const char optsync[] =
+"[-?\n@(#)$Id: sync (AT&T Research) 2013-07-28 $\n]"
+"[-author?Roland Mainz <roland.mainz at nrubsig.org>]"
+"[+NAME?sync - schedule file/file system updates]"
+"[+DESCRIPTION?\bsync\b(1) issues either the transfer of all data to "
+ "storage for an individual file descriptor, the associated "
+ "filesystem for a file descriptor or all file data in the "
+ "whole system.]"
+/* -f is reserved for |fflush()| - if we ever want to implement it */
+#ifdef _lib_fsync
+"[s]#[fsync:fd?All data for the open file descriptor is to be transferred "
+ "to the storage device associated with the file described by "
+ "fildes via calling \bfsync\b(2). The utility will not return "
+ "until the system has completed that action or until an error "
+ "is detected.]"
+#endif
+#ifdef _lib_syncfs
+"[S]#[syncfs:fd?Synchronizes just the file system containing file referred to "
+ "by the open file descriptor fd by calling \bsyncfs\b(2).]"
+#endif
+#ifdef _lib_sync
+"[X:sync?Causes all information in memory that updates file systems to be "
+ "scheduled for writing out to all file systems by calling "
+ "\bsync\b(2). The writing, although scheduled, is not necessarily "
+ "complete upon return from \bsync\b. "
+ "Since \bsync\b(2) has no failure indication, \bsync\b only fails for "
+ "option/operand syntax errors, or when \bsync\b(2) does not return, in "
+ "which case \bsync\b(1) also does not return.]"
+#endif
+"[+?Option \b-X\b is implied if no other option is given.]"
+
+"[+?At minimum \bsync\b (without options) should be called before halting "
+ "the system. Most systems provide graceful shutdown procedures that "
+ "include \bsync\b -- use them if possible.]"
+"[+SEE ALSO?\bsync\b(2), \bfsync\b(2), \bsyncfs\b(2), \bshutdown\b(8)]"
+;
+

int
b_sync(int argc, char** argv, Shbltin_t* context)
{
- cmdinit(argc, argv, context, ERROR_CATALOG, 0);
+ NOT_USED(context);
+#ifdef _lib_fsync
+ int fsync_fd = -1;
+#endif
+#ifdef _lib_syncfs
+ int syncfs_fd = -1;
+#endif
+ bool do_sync = false;
+ bool failure = false;
+
for (;;)
{
- switch (optget(argv, usage))
+ switch (optget(argv, optsync))
{
+ /* -f is reserved for |fflush()| - if we ever want to implement it */
+#ifdef _lib_fsync
+ case 's':
+ fsync_fd = opt_info.num;
+ break;
+#endif
+#ifdef _lib_syncfs
+ case 'S':
+ syncfs_fd = opt_info.num;
+ break;
+#endif
+#ifdef _lib_sync
+ case 'X':
+ do_sync = true;
+ break;
+#endif
case ':':
error(2, "%s", opt_info.arg);
break;
@@ -70,10 +111,70 @@
argv += opt_info.index;
if (error_info.errors || *argv)
error(ERROR_usage(2), "%s", optusage(NiL));
+
+ if (
+#ifdef _lib_fsync
+ (fsync_fd == -1) &&
+#endif
+#ifdef _lib_syncfs
+ (syncfs_fd == -1) &&
+#endif
+ true)
+ do_sync = true;
+
+#ifdef _lib_fsync
+ if (fsync_fd >= 0)
+ {
+ if (fsync(fsync_fd) < 0)
+ {
+ error(ERROR_system(0), "fsync(%d) failed", fsync_fd);
+ failure = true;
+ }
+ }
+#endif
+
+ if (
+#ifdef _lib_syncfs
+ (syncfs_fd >= 0) ||
+#endif
+ do_sync)
+ {
+ /*
+ * sync all streams. We do this for two reasons:
+ * 1. All data we buffer internally are flushed first
+ * to prevent that something important gets lost if
+ * the machine looses power immediately after the
+ * sync(1) call
+ * 2. Sometimes sync(1) is used to reach a "stable
+ * state on disk". We can't meet this expectation if
+ * we keep data buffered internally, call the sync(1)
+ * builtin and then ruin the stable state by
+ * immediately afterwards flushing some bits of data
+ * to the filesystem buffers to make the state on
+ * disk "stale" again.
+ */
+ sfsync(NiL);
+ }
+
+#ifdef _lib_syncfs
+ if (syncfs_fd >= 0)
+ {
+ if (syncfs(syncfs_fd) < 0)
+ {
+ error(ERROR_system(0), "syncfs(%d) failed", syncfs_fd);
+ failure = true;
+ }
+ }
+#endif
+ if (do_sync)
+ {
#if _lib_sync
- sync();
+ sync();
#else
- error(ERROR_usage(2), "failed -- the native system does not provide a sync(2) call");
+ error(ERROR_usage(2), "failed -- the native system does not provide a sync(2) call");
#endif
- return 0;
+ }
+
+ return failure?1:0;
}
+
Loading...