program). I'm not sure where the NFS stuff is discussed, but
there's probably a public forum somewhere.
Post by Ulrich Windl# non-root calling exportfs
./exportfs; echo $?
exportfs: could not open /var/lib/nfs/.etab.lock for locking: errno 13 (Permission denied)
1
# Empty export list
# ./exportfs; echo $?
0
# ./exportfs no-such-host:/tmp; echo $?
exportfs: Failed to resolve no-such-host
1
# existing host and filesystem
rksapv04:/tmp # ./exportfs localhost:/tmp; echo $?
0
# non-existing filesystem or directory
# ./exportfs localhost:/no-such-file; echo $?
exportfs: Failed to stat /no-such-file: No such file or directory
exportfs: localhost:/no-such-file: No such file or directory
1
# both incorrect
# ./exportfs no-host:/no-file; echo $?
exportfs: Failed to resolve no-host
exportfs: localhost:/no-such-file: No such file or directory
1
# ./exportfs ; echo $?
/tmp localhost
/no-such-file localhost
0
# At least it can be unexported
# ./exportfs -u localhost:/no-such-file; echo $?
0
So the patch is not perfect, but probably a good staring point. Please send feedback!
Regards,
Ulrich
Post by Ulrich WindlPost by Ulrich WindlPost by Ulrich WindlDejan Muhamedagic <dejanmm at fastmail.fm> schrieb am 01.02.2013 um 08:53 in
Hi,
Post by Ulrich WindlHi!
While trying to develop an improved exportfs RA that can export one
exportfs is returning exit code 0 even if the filesystem could not be
exported, like in
Post by Ulrich Windlh02:~ # exportfs h012:/mnt; echo $? # h012 does not exist
exportfs: Failed to resolve h012
0
Accordingly the start operation for the exportfs alway reports success,
even if the operation failed! That's due to
Post by Ulrich Windl[...]
ocf_run exportfs -v ${OPTIONS}
${OCF_RESKEY_clientspec}:${OCF_RESKEY_directory} || exit $OCF_ERR_GENERIC
Post by Ulrich Windl# Restore the rmtab to ensure smooth NFS-over-TCP failover
restore_rmtab
ocf_log info "File system exported"
return $OCF_SUCCESS
[...]
However the monitor operation does the correct thing, thus reporting an
error (rc==7).
We could insert the monitor operation after the call to exportfs.
Would there be any timing issues? I guess not.
Thanks,
Dejan
Hi!
I'd fix the root of the problem: exportfs is unreliable!
Regards,
Ulrich
Post by Ulrich WindlPost by Ulrich Windl* rc=1: Monitoring an active resource should return 0
(The tester thinks the resource was started when it was not)
I had reported this for SLES10 SP2 to support in November, but after a long
time of waiting and repeating the same facts over and over, support told me
it's "working as designed"; lvscan and lvcreate would be similar.
Post by Ulrich Windl# lvcreate -n bar -L40G foobar; echo $?
Volume group "foobar" not found
5
# lvcreate -n foo -L1T sys; echo $?
Volume group "sys" has insufficient free space (1855 extents): 32768
required.
Post by Ulrich Windl5
I got the impression that my support is just unwilling to fix the rather
trivial problem. My exportfs comes from nfs-kernel-server-1.2.3-18.23.1.
Post by Ulrich WindlGetting the exportfs sources, it took me two minutes to find out that
exportfs uses variable export_errno to define the exit code, and that
variable is nowhere set. The worker routine exportfs() does return nothing
at
Post by Ulrich Windlall. What a design!
Post by Ulrich WindlHere's an example from an old HP-UX system that didn't get any updates for
# exportfs nohost:/mnt; echo $?
exportfs: no entry for nohost:/mnt in /etc/dfs/dfstab
1
Here it works!
I wonder why some Linux people are so ignorant occasionally...
Regards,
Ulrich
_______________________________________________
Linux-HA mailing list
Linux-HA at lists.linux-ha.org
http://lists.linux-ha.org/mailman/listinfo/linux-ha
See also: http://linux-ha.org/ReportingProblems
_______________________________________________
Linux-HA mailing list
Linux-HA at lists.linux-ha.org
http://lists.linux-ha.org/mailman/listinfo/linux-ha
See also: http://linux-ha.org/ReportingProblems
From 11c4a0d45a06169f2de8bd220509f4569a5c37c2 Mon Sep 17 00:00:00 2001
From: Ulrich Windl <Ulrich.Windl at RZ.Uni-Regensburg.DE>
Date: Wed, 13 Feb 2013 11:45:33 +0100
Subject: [PATCH 1/2] Include <stdio.h> for snprintf()
Include <stdio.h> to declare snprintf() in utils/nfsdcltrack/sqlite.c.
---
utils/nfsdcltrack/sqlite.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/utils/nfsdcltrack/sqlite.c b/utils/nfsdcltrack/sqlite.c
index bac6789..f825873 100644
--- a/utils/nfsdcltrack/sqlite.c
+++ b/utils/nfsdcltrack/sqlite.c
@@ -38,6 +38,7 @@
#include "config.h"
#endif /* HAVE_CONFIG_H */
+#include <stdio.h>
#include <dirent.h>
#include <errno.h>
#include <event.h>
--
1.7.12.4
From eaaa966427e64b247f67a22df3ed87fe6dd61923 Mon Sep 17 00:00:00 2001
From: Ulrich Windl <Ulrich.Windl at RZ.Uni-Regensburg.DE>
Date: Wed, 13 Feb 2013 13:24:54 +0100
Subject: [PATCH 2/2] Let exportfs exit with error on errors
xtab_read() and xtab_export_read() will return 0 on errors (strange logic,
but according to existing code).
cache_flush() will return 0 on success.
Changed export_all(), exportfs(), unexportfs(), exports_update(),
validate_export(), grab_lockfile(), release_lockfile() to return 0 on
success. Added verbose_release_lockfile() to keep atexit() happy.
Changed main() to return 1 on failure of any of: cache_flush(),
xtab_export_read(), grab_lockfile(), export_all(), exportfs(),
unexportfs(), exports_update(), xtab_export_write(), xtab_mount_write()
Changed exports_update_one() to return 0 on success, watching
export_export() and export_unexport() for errors.
Changed exports_update() to return 0 on success, watching
exports_update_one() for errors.
Changed export_all() to return 0 on success watching validate_export() for
errors.
Changed exportfs() to return 0 on success, watching updateexportent() and
validate_export() for errors.
Changed validate_export() to return 0 on success, watching test_export()
for errors.
---
support/export/xtab.c | 4 +-
support/include/nfslib.h | 2 +-
support/nfs/cacheio.c | 5 +-
utils/exportfs/exportfs.c | 173 ++++++++++++++++++++++++++++++----------------
4 files changed, 120 insertions(+), 64 deletions(-)
diff --git a/support/export/xtab.c b/support/export/xtab.c
index 2a43193..a87d453 100644
--- a/support/export/xtab.c
+++ b/support/export/xtab.c
@@ -24,6 +24,7 @@
int v4root_needed;
static void cond_rename(char *newfile, char *oldfile);
+/* return 0 on failure! */
static int
xtab_read(char *xtab, char *lockfn, int is_export)
{
@@ -63,7 +64,7 @@ xtab_read(char *xtab, char *lockfn, int is_export)
endexportent();
xfunlock(lockid);
- return 0;
+ return 1;
}
int
@@ -93,6 +94,7 @@ xtab_export_read(void)
* inode number changes when the xtab_export_write is done. If you change the
* routine below such that the files are edited in place, then you'll need to
* fix the auth_reload logic as well...
+ * Return 0 on failure!
*/
static int
xtab_write(char *xtab, char *xtabtmp, char *lockfn, int is_export)
diff --git a/support/include/nfslib.h b/support/include/nfslib.h
index f210a06..ee45f56 100644
--- a/support/include/nfslib.h
+++ b/support/include/nfslib.h
@@ -155,7 +155,7 @@ int qword_eol(FILE *f);
int readline(int fd, char **buf, int *lenp);
int qword_get(char **bpp, char *dest, int bufsize);
int qword_get_int(char **bpp, int *anint);
-void cache_flush(int force);
+int cache_flush(int force);
int check_new_cache(void);
void qword_add(char **bpp, int *lp, char *str);
void qword_addhex(char **bpp, int *lp, char *buf, int blen);
diff --git a/support/nfs/cacheio.c b/support/nfs/cacheio.c
index e641c45..7ffca97 100644
--- a/support/nfs/cacheio.c
+++ b/support/nfs/cacheio.c
@@ -321,7 +321,7 @@ check_new_cache(void)
* auth.unix.ip nfsd.export nfsd.fh
*/
-void
+int
cache_flush(int force)
{
struct stat stb;
@@ -329,6 +329,7 @@ cache_flush(int force)
char stime[20];
char path[200];
time_t now;
+ int result = 0;
/* Note: the order of these caches is important.
* They need to be flushed in dependancy order. So
* a cache that references items in another cache,
@@ -357,8 +358,10 @@ cache_flush(int force)
if (write(fd, stime, strlen(stime)) != (ssize_t)strlen(stime)) {
xlog_warn("Writing to '%s' failed: errno %d (%s)",
path, errno, strerror(errno));
+ result = 1;
}
close(fd);
}
}
+ return result;
}
diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c
index 9f79541..27ac8c3 100644
--- a/utils/exportfs/exportfs.c
+++ b/utils/exportfs/exportfs.c
@@ -34,18 +34,19 @@
#include "exportfs.h"
#include "xlog.h"
-static void export_all(int verbose);
-static void exportfs(char *arg, char *options, int verbose);
-static void unexportfs(char *arg, int verbose);
-static void exports_update(int verbose);
+static int export_all(int verbose);
+static int exportfs(char *arg, char *options, int verbose);
+static int unexportfs(char *arg, int verbose);
+static int exports_update(int verbose);
static void dump(int verbose);
static void error(nfs_export *exp, int err);
static void usage(const char *progname, int n);
-static void validate_export(nfs_export *exp);
+static int validate_export(nfs_export *exp);
static int matchhostname(const char *hostname1, const char *hostname2);
static void export_d_read(const char *dname);
-static void grab_lockfile(void);
-static void release_lockfile(void);
+static int grab_lockfile(void);
+static int release_lockfile(void);
+static void verbose_release_lockfile(void);
static const char *lockfile = EXP_LOCKFILE;
static int _lockfd = -1;
@@ -66,18 +67,28 @@ static int _lockfd = -1;
* corrupting etab, but to prevent problems like the above we
* need these additional lockfile() routines.
*/
-static void
+static int
grab_lockfile()
{
_lockfd = open(lockfile, O_CREAT|O_RDWR, 0666);
- if (_lockfd != -1)
- lockf(_lockfd, F_LOCK, 0);
+ if (_lockfd != -1 && lockf(_lockfd, F_LOCK, 0) == 0)
+ return 0;
+ return 1;
}
-static void
+
+static int
release_lockfile()
{
- if (_lockfd != -1)
- lockf(_lockfd, F_ULOCK, 0);
+ if (_lockfd != -1 && lockf(_lockfd, F_ULOCK, 0) == 0)
+ return 0;
+ return 1;
+}
+
+static void
+verbose_release_lockfile()
+{
+ if (release_lockfile())
+ xlog(L_ERROR, "problem releasing lockfile %s: %m", lockfile);
}
int
@@ -153,38 +164,44 @@ main(int argc, char **argv)
new_cache = check_new_cache();
if (optind == argc && ! f_all) {
if (force_flush) {
- if (new_cache)
- cache_flush(1);
- else {
+ if (new_cache) {
+ if (cache_flush(1))
+ export_errno = 1;
+ } else {
xlog(L_ERROR, "-f is available only "
"with new cache controls. "
"Mount /proc/fs/nfsd first");
return 1;
}
- return 0;
+ return export_errno;
} else {
- xtab_export_read();
+ if (xtab_export_read() == 0)
+ export_errno = 1;
dump(f_verbose);
- return 0;
+ return export_errno;
}
}
/*
* Serialize things as best we can
*/
- grab_lockfile();
- atexit(release_lockfile);
+ if (grab_lockfile())
+ export_errno = 1;
+ atexit(verbose_release_lockfile);
if (f_export && ! f_ignore) {
export_read(_PATH_EXPORTS);
export_d_read(_PATH_EXPORTS_D);
}
if (f_export) {
- if (f_all)
- export_all(f_verbose);
- else
- for (i = optind; i < argc ; i++)
- exportfs(argv[i], options, f_verbose);
+ if (f_all) {
+ if (export_all(f_verbose))
+ export_errno = 1;
+ } else
+ for (i = optind; i < argc ; i++) {
+ if (exportfs(argv[i], options, f_verbose))
+ export_errno = 1;
+ }
}
/* If we are unexporting everything, then
* don't care about what should be exported, as that
@@ -194,30 +211,41 @@ main(int argc, char **argv)
/* note: xtab_*_read does not update entries if they already exist,
* so this will not lose new options
*/
- if (!f_reexport)
- xtab_export_read();
+ if (!f_reexport) {
+ if (xtab_export_read() == 0)
+ export_errno = 1;
+ }
if (!f_export)
- for (i = optind ; i < argc ; i++)
- unexportfs(argv[i], f_verbose);
+ for (i = optind ; i < argc ; i++) {
+ if (unexportfs(argv[i], f_verbose))
+ export_errno = 1;
+ }
if (!new_cache)
rmtab_read();
}
if (!new_cache) {
xtab_mount_read();
- exports_update(f_verbose);
+ if (exports_update(f_verbose))
+ export_errno = 1;
+ }
+ if (!xtab_export_write())
+ export_errno = 1;
+ if (new_cache) {
+ if (cache_flush(force_flush))
+ export_errno = 1;
}
- xtab_export_write();
- if (new_cache)
- cache_flush(force_flush);
if (!new_cache)
- xtab_mount_write();
+ if (!xtab_mount_write())
+ export_errno = 1;
return export_errno;
}
-static void
+static int
exports_update_one(nfs_export *exp, int verbose)
{
+ int result = 0;
+
/* check mountpoint option */
if (exp->m_mayexport &&
exp->m_export.e_mountpoint &&
@@ -227,6 +255,7 @@ exports_update_one(nfs_export *exp, int verbose)
printf("%s not exported as %s not a mountpoint.\n",
exp->m_export.e_path, exp->m_export.e_mountpoint);
exp->m_mayexport = 0;
+ result = 1;
}
if (exp->m_mayexport && ((exp->m_exported<1) || exp->m_changed)) {
if (verbose)
@@ -234,17 +263,22 @@ exports_update_one(nfs_export *exp, int verbose)
exp->m_exported ?"re":"",
exp->m_client->m_hostname,
exp->m_export.e_path);
- if (!export_export(exp))
+ if (!export_export(exp)) {
error(exp, errno);
+ result = 1;
+ }
}
if (exp->m_exported && ! exp->m_mayexport) {
if (verbose)
printf("unexporting %s:%s from kernel\n",
exp->m_client->m_hostname,
exp->m_export.e_path);
- if (!export_unexport(exp))
+ if (!export_unexport(exp)) {
error(exp, errno);
+ result = 1;
+ }
}
+ return result;
}
@@ -253,28 +287,33 @@ exports_update_one(nfs_export *exp, int verbose)
* entries with m_exported but not m_mayexport get unexported
* looking at m_client->m_type == MCL_FQDN and m_client->m_type == MCL_GSS only
*/
-static void
+static int
exports_update(int verbose)
{
nfs_export *exp;
+ int result = 0;
for (exp = exportlist[MCL_FQDN].p_head; exp; exp=exp->m_next) {
- exports_update_one(exp, verbose);
+ if (exports_update_one(exp, verbose))
+ result = 1;
}
for (exp = exportlist[MCL_GSS].p_head; exp; exp=exp->m_next) {
- exports_update_one(exp, verbose);
+ if (exports_update_one(exp, verbose))
+ result = 1;
}
+ return result;
}
/*
- * export_all finds all entries and
- * marks them xtabent and mayexport so that they get exported
+ * export_all finds all entries and marks them xtabent and mayexport so that
+ * they get exported. Return 0 if thewre were no errors.
*/
-static void
+static int
export_all(int verbose)
{
nfs_export *exp;
int i;
+ int result = 0;
for (i = 0; i < MCL_MAXTYPES; i++) {
for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
@@ -286,13 +325,15 @@ export_all(int verbose)
exp->m_mayexport = 1;
exp->m_changed = 1;
exp->m_warned = 0;
- validate_export(exp);
+ if (validate_export(exp))
+ result = 1;
}
}
+ return result;
}
-
-static void
+/* return 0 on success */
+static int
exportfs(char *arg, char *options, int verbose)
{
struct exportent *eep;
@@ -301,13 +342,14 @@ exportfs(char *arg, char *options, int verbose)
char *path;
char *hname = arg;
int htype;
+ int result = 0;
if ((path = strchr(arg, ':')) != NULL)
*path++ = '\0';
if (!path || *path != '/') {
xlog(L_ERROR, "Invalid exporting option: %s", arg);
- return;
+ return 1;
}
if ((htype = client_gettype(hname)) == MCL_FQDN) {
@@ -321,10 +363,14 @@ exportfs(char *arg, char *options, int verbose)
if (!exp) {
if (!(eep = mkexportent(hname, path, options)) ||
- !(exp = export_create(eep, 0)))
+ !(exp = export_create(eep, 0))) {
+ result = 1;
goto out;
- } else if (!updateexportent(&exp->m_export, options))
+ }
+ } else if (!updateexportent(&exp->m_export, options)) {
+ result = 1;
goto out;
+ }
if (verbose)
printf("exporting %s:%s\n", exp->m_client->m_hostname,
@@ -333,13 +379,15 @@ exportfs(char *arg, char *options, int verbose)
exp->m_mayexport = 1;
exp->m_changed = 1;
exp->m_warned = 0;
- validate_export(exp);
+ result = validate_export(exp);
freeaddrinfo(ai);
+ return result;
}
-static void
+/* return 0 on success */
+static int
unexportfs(char *arg, int verbose)
{
nfs_export *exp;
@@ -347,13 +395,14 @@ unexportfs(char *arg, int verbose)
char *path;
char *hname = arg;
int htype;
+ int result = 0;
if ((path = strchr(arg, ':')) != NULL)
*path++ = '\0';
if (!path || *path != '/') {
xlog(L_ERROR, "Invalid unexporting option: %s", arg);
- return;
+ return 1;
}
if ((htype = client_gettype(hname)) == MCL_FQDN) {
@@ -396,6 +445,7 @@ unexportfs(char *arg, int verbose)
}
freeaddrinfo(ai);
+ return result;
}
static int can_test(void)
@@ -433,10 +483,11 @@ static int test_export(char *path, int with_fsid)
return 1;
}
-static void
+static int
validate_export(nfs_export *exp)
{
- /* Check that the given export point is potentially exportable.
+ /* Check that the given export point is potentially exportable,
+ * returning 0 on success.
* We just give warnings here, don't cause anything to fail.
* If a path doesn't exist, or is not a dir or file, give an warning
* otherwise trial-export to '-test-client-' and check for failure.
@@ -448,15 +499,15 @@ validate_export(nfs_export *exp)
if (stat(path, &stb) < 0) {
xlog(L_ERROR, "Failed to stat %s: %m", path);
- return;
+ return 1;
}
if (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) {
xlog(L_ERROR, "%s is neither a directory nor a file. "
"Remote access will fail", path);
- return;
+ return 1;
}
if (!can_test())
- return;
+ return 1;
if (!statfs64(path, &stf) &&
(stf.f_fsid.__val[0] || stf.f_fsid.__val[1]))
@@ -466,16 +517,16 @@ validate_export(nfs_export *exp)
fs_has_fsid) {
if ( !test_export(path, 1)) {
xlog(L_ERROR, "%s does not support NFS export", path);
- return;
+ return 1;
}
} else if ( ! test_export(path, 0)) {
if (test_export(path, 1))
xlog(L_ERROR, "%s requires fsid= for NFS export", path);
else
xlog(L_ERROR, "%s does not support NFS export", path);
- return;
-
+ return 1;
}
+ return 0;
}
static _Bool
--
1.7.12.4
_______________________________________________
Linux-HA mailing list
Linux-HA at lists.linux-ha.org
http://lists.linux-ha.org/mailman/listinfo/linux-ha
See also: http://linux-ha.org/ReportingProblems