+2009-02-12 Christos Zoulas <christos@zoulas.com>
+
+ * Add a synchronous unmount amq rpc that will wait for the remote
+ filesystem to be unmounted, or return an error. Enabled by amq -uu
+
2009-01-11 Erez Zadok <ezk@fsl.cs.sunysb.edu>
* amd/ops_udf.c: don't define functions/variables which may not be
#ifdef HAVE_FS_AUTOFS
int autofs_fs_flags;/* filesystem flags FS_* for autofs mounts */
#endif /* HAVE_FS_AUTOFS */
+ int am_fd[2]; /* parent child pipe fd's for sync umount */
};
/*
extern int *amqproc_mount_1_svc(voidp argp, struct svc_req *rqstp);
extern int *amqproc_setopt_1_svc(voidp argp, struct svc_req *rqstp);
extern voidp amqproc_null_1_svc(voidp argp, struct svc_req *rqstp);
-extern voidp amqproc_umnt_1_svc(voidp argp, struct svc_req *rqstp);
+extern int *amqproc_umnt_1_svc(voidp argp, struct svc_req *rqstp);
+extern int *amqproc_sync_umnt_1_svc_parent(voidp argp, struct svc_req *rqstp);
+extern amq_sync_umnt *amqproc_sync_umnt_1_svc_child(voidp argp, struct svc_req *rqstp);
+extern amq_sync_umnt *amqproc_sync_umnt_1_svc_async(voidp argp, struct svc_req *rqstp);
/* other external definitions */
extern am_nfs_fh *get_root_nfs_fh(char *dir);
extern void new_ttl(am_node *);
extern void nfs_quick_reply(am_node *mp, int error);
extern void normalize_slash(char *);
+extern void notify_child(am_node *, au_etype, int, int);
extern void ops_showamfstypes(char *buf, size_t l);
extern void ops_showfstypes(char *outbuf, size_t l);
extern void rem_que(qelem *);
/*
* Unmount a single node
*/
-voidp
+int *
amqproc_umnt_1_svc(voidp argp, struct svc_req *rqstp)
{
- static char res;
+ static int res = AMQ_UMNT_OK;
am_node *mp = find_ap(*(char **) argp);
if (mp)
forcibly_timeout_mp(mp);
- return (voidp) &res;
+ return &res;
+}
+
+
+/*
+ * Synchronously unmount a single node - parent side.
+ */
+int *
+amqproc_sync_umnt_1_svc_parent(voidp argp, struct svc_req *rqstp)
+{
+ amqproc_umnt_1_svc(argp, rqstp);
+ return NULL;
+}
+
+
+/*
+ * Synchronously unmount a single node - child side.
+ */
+amq_sync_umnt *
+amqproc_sync_umnt_1_svc_child(voidp argp, struct svc_req *rqstp)
+{
+ static amq_sync_umnt rv;
+ amq_sync_umnt buf;
+ ssize_t n;
+
+ am_node *mp = find_ap(*(char **) argp);
+
+ memset(&rv, 0, sizeof(rv));
+ rv.au_etype = AMQ_UMNT_READ;
+ if (mp && mp->am_fd[0] >= 0) {
+ n = read(mp->am_fd[0], &buf, sizeof(buf));
+ if (n == sizeof(buf))
+ rv = buf;
+ }
+ return &rv;
+}
+
+
+/*
+ * Synchronously unmount a single node - use if we can't fork (asynchronous).
+ */
+amq_sync_umnt *
+amqproc_sync_umnt_1_svc_async(voidp argp, struct svc_req *rqstp)
+{
+ static amq_sync_umnt rv;
+
+ memset(&rv, 0, sizeof(rv));
+ rv.au_etype = AMQ_UMNT_FORK;
+ rv.au_errno = errno;
+
+ amqproc_umnt_1_svc(argp, rqstp);
+
+ return &rv;
}
#endif /* defined(HAVE_TCPD_H) && defined(HAVE_LIBWRAP) */
+/*
+ * Prepare the parent and child:
+ * 1) Setup IPC pipe.
+ * 2) Set signal masks.
+ * 3) Fork by calling background() so that NumChildren is updated.
+ */
+static int
+amq_fork(opaque_t argp)
+{
+#ifdef HAVE_SIGACTION
+ sigset_t new, mask;
+#else /* not HAVE_SIGACTION */
+ int mask;
+#endif /* not HAVE_SIGACTION */
+ am_node *mp;
+ pid_t pid;
+
+ mp = find_ap(*(char **) argp);
+ if (mp == NULL) {
+ errno = 0;
+ return -1;
+ }
+
+ if (pipe(mp->am_fd) == -1) {
+ mp->am_fd[0] = -1;
+ mp->am_fd[1] = -1;
+ return -1;
+ }
+
+#ifdef HAVE_SIGACTION
+ sigemptyset(&new); /* initialize signal set we wish to block */
+ sigaddset(&new, SIGHUP);
+ sigaddset(&new, SIGINT);
+ sigaddset(&new, SIGQUIT);
+ sigaddset(&new, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &new, &mask);
+#else /* not HAVE_SIGACTION */
+ mask =
+ sigmask(SIGHUP) |
+ sigmask(SIGINT) |
+ sigmask(SIGQUIT) |
+ sigmask(SIGCHLD);
+ mask = sigblock(mask);
+#endif /* not HAVE_SIGACTION */
+
+ switch ((pid = background())) {
+ case -1: /* error */
+ dlog("amq_fork failed");
+ return -1;
+
+ case 0: /* child */
+ close(mp->am_fd[1]); /* close output end of pipe */
+ mp->am_fd[1] = -1;
+ return 0;
+
+ default: /* parent */
+ close(mp->am_fd[0]); /* close input end of pipe */
+ mp->am_fd[0] = -1;
+
+#ifdef HAVE_SIGACTION
+ sigprocmask(SIG_SETMASK, &mask, NULL);
+#else /* not HAVE_SIGACTION */
+ sigsetmask(mask);
+#endif /* not HAVE_SIGACTION */
+ return pid;
+ }
+}
+
+
void
amq_program_1(struct svc_req *rqstp, SVCXPRT *transp)
{
char *result;
xdrproc_t xdr_argument, xdr_result;
amqsvcproc_t local;
+ amqsvcproc_t child;
+ amqsvcproc_t parent;
+ pid_t pid;
#if defined(HAVE_TCPD_H) && defined(HAVE_LIBWRAP)
if (gopt.flags & CFM_USE_TCPWRAPPERS) {
}
#endif /* defined(HAVE_TCPD_H) && defined(HAVE_LIBWRAP) */
+ local = NULL;
+ child = NULL;
+ parent = NULL;
+
switch (rqstp->rq_proc) {
case AMQPROC_NULL:
local = (amqsvcproc_t) amqproc_pawd_1_svc;
break;
+ case AMQPROC_SYNC_UMNT:
+ xdr_argument = (xdrproc_t) xdr_amq_string;
+ xdr_result = (xdrproc_t) xdr_amq_sync_umnt;
+ parent = (amqsvcproc_t) amqproc_sync_umnt_1_svc_parent;
+ child = (amqsvcproc_t) amqproc_sync_umnt_1_svc_child;
+ /* used if fork fails */
+ local = (amqsvcproc_t) amqproc_sync_umnt_1_svc_async;
+ break;
+
default:
svcerr_noproc(transp);
return;
return;
}
- result = (*local) (&argument, rqstp);
+ pid = -1;
+ result = NULL;
+
+ if (child) {
+ switch ((pid = amq_fork(&argument))) {
+ case -1: /* error */
+ break;
+
+ case 0: /* child */
+ result = (*child) (&argument, rqstp);
+ local = NULL;
+ break;
+
+ default: /* parent */
+ result = (*parent) (&argument, rqstp);
+ local = NULL;
+ break;
+ }
+ }
+
+ if (local)
+ result = (*local) (&argument, rqstp);
if (result != NULL && !svc_sendreply(transp,
(XDRPROC_T_TYPE) xdr_result,
plog(XLOG_FATAL, "unable to free rpc arguments in amqprog_1");
going_down(1);
}
+
+ if (pid == 0)
+ exit(0); /* the child is done! */
}
*/
if (mf && ((mp->am_flags & AMF_ROOT) ||
(mf->mf_flags & (MFF_MOUNTING | MFF_UNMOUNTING)))) {
+ /*
+ * We aren't going to schedule a timeout, so we need to notify the
+ * child here unless we are already unmounting, in which case that
+ * process is responsible for notifying the child.
+ */
if (mf->mf_flags & MFF_UNMOUNTING)
plog(XLOG_WARNING, "node %s is currently being unmounted, ignoring timeout request", mp->am_path);
- else
+ else {
plog(XLOG_WARNING, "ignoring timeout request for active node %s", mp->am_path);
+ notify_child(mp, AMQ_UMNT_FAILED, EBUSY, 0);
+ }
} else {
plog(XLOG_INFO, "\"%s\" forcibly timed out", mp->am_path);
mp->am_flags &= ~AMF_NOTIMEOUT;
{
mntfs *mf = mp->am_mnt;
- if (!foreground) /* firewall - should never happen */
+ if (!foreground) { /* firewall - should never happen */
+ /*
+ * This is a coding error. Make sure we hear about it!
+ */
+ plog(XLOG_FATAL, "am_unmounted: illegal use in background (%s)",
+ mp->am_name);
+ notify_child(mp, AMQ_UMNT_OK, 0, 0); /* XXX - be safe? */
return;
+ }
/*
* Do unmounted callback
char *fname = strdup(mp->am_name);
am_node *mp_parent = mp->am_parent;
mntfs *mf_parent = mp_parent->am_mnt;
+ am_node fake_mp;
int error = 0;
+ /*
+ * We need to use notify_child() after free_map(), so save enough
+ * to do that in fake_mp.
+ */
+ fake_mp.am_fd[1] = mp->am_fd[1];
+ mp->am_fd[1] = -1;
+
free_map(mp);
plog(XLOG_INFO, "am_unmounted: remounting %s", fname);
mp = mf_parent->mf_ops->lookup_child(mp_parent, fname, &error, VLOOK_CREATE);
if (error > 0) {
errno = error;
plog(XLOG_ERROR, "am_unmounted: could not remount %s: %m", fname);
+ notify_child(&fake_mp, AMQ_UMNT_OK, 0, 0);
+ } else {
+ notify_child(&fake_mp, AMQ_UMNT_FAILED, EBUSY, 0);
}
XFREE(fname);
- } else
+ } else {
/*
* We have a race here.
* If this node has a pending mount and amd is going down (unmounting
* We avoid the race by refusing to free any nodes that have
* pending mounts (defined as having a non-NULL am_mfarray).
*/
+ notify_child(mp, AMQ_UMNT_OK, 0, 0); /* do this regardless */
if (!mp->am_mfarray)
free_map(mp);
+ }
}
mp->am_stats.s_mtime = mp->am_fattr.na_atime.nt_seconds;
mp->am_dev = -1;
mp->am_rdev = -1;
+ mp->am_fd[0] = -1;
+ mp->am_fd[1] = -1;
+}
+
+
+void
+notify_child(am_node *mp, au_etype au_etype, int au_errno, int au_signal)
+{
+ amq_sync_umnt rv;
+
+ if (mp->am_fd[1] >= 0) { /* we have a child process */
+ rv.au_etype = au_etype;
+ rv.au_signal = au_signal;
+ rv.au_errno = au_errno;
+
+ write(mp->am_fd[1], &rv, sizeof(rv));
+ close(mp->am_fd[1]);
+ mp->am_fd[1] = -1;
+ }
}
{
remove_am(mp);
+ if (mp->am_fd[1] != -1)
+ plog(XLOG_FATAL, "free_map: called prior to notifying the child for %s.",
+ mp->am_path);
+
if (mp->am_link)
XFREE(mp->am_link);
if (mp->am_name)
reschedule_timeout_mp();
}
if (term) {
+ notify_child(mp, AMQ_UMNT_SIGNAL, 0, term);
plog(XLOG_ERROR, "unmount for %s got signal %d", mp->am_path, term);
#if defined(DEBUG) && defined(SIGTRAP)
/*
#endif /* HAVE_FS_AUTOFS */
amd_stats.d_uerr++;
} else if (rc) {
+ notify_child(mp, AMQ_UMNT_FAILED, rc, 0);
if (mf->mf_ops == &amfs_program_ops || rc == EBUSY)
plog(XLOG_STATS, "\"%s\" on %s still active", mp->am_path, mf->mf_mount);
else
#endif /* HAVE_FS_AUTOFS */
amd_stats.d_uerr++;
} else {
+ /*
+ * am_unmounted() will call notify_child() appropriately.
+ */
am_unmounted(mp);
}
plog(XLOG_STATS, "file server %s is down - timeout of \"%s\" ignored", mf->mf_server->fs_host, mp->am_path);
mf->mf_flags |= MFF_LOGDOWN;
}
+ notify_child(mp, AMQ_UMNT_SERVER, 0, 0);
return 0;
}
.SH SYNOPSIS
.B amq
[
-.BI \-fmpsvwHTU
+.BI \-fmpqsvwHTU
] [
.BI \-h " hostname"
] [
.I ctl-amd
script.
+.TP
+.B \-q
+Suppress error messages produced when attempting synchronous unmounts
+with the
+.B \-u
+option.
+
.TP
.B \-s
Ask the automounter to provide system-wide mount statistics.
cause the mounted filesystem to timeout, which will be picked up by
.BR amd 's
main scheduler thus causing the normal timeout action to be taken.
+If the
+.B \-u
+option is repeated,
+.B amq
+will attempt to unmount the file system synchronously by waiting until
+the timeout action is taken and returning an error if the unmount
+fails.
+Any error messages produced may be suppressed with the
+.B \-q
+option.
.TP
.B \-v
.SH "SEE ALSO"
.BR amd (8),
-.BR ctl-amd (8),
+.\" .BR ctl-amd (8),
.BR amd.conf (5),
.BR hosts_access (5).
.LP
/* locals */
static int flush_flag;
-static int minfo_flag;
static int getpid_flag;
-static int unmount_flag;
-static int stats_flag;
+static int getpwd_flag;
static int getvers_flag;
+static int minfo_flag;
+static int quiet_flag;
+static int stats_flag;
+static int unmount_flag;
+static int use_tcp_flag;
+static int use_udp_flag;
static u_long amd_program_number = AMQ_PROGRAM;
-static int use_tcp_flag, use_udp_flag;
-static int getpwd_flag;
static char *debug_opts;
static char *amq_logfile;
static char *xlog_optstr;
#endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */
+static void
+print_umnt_error(amq_sync_umnt *rv, const char *fs)
+{
+
+ switch (rv->au_etype) {
+ case AMQ_UMNT_OK:
+ break;
+ case AMQ_UMNT_FAILED:
+ printf("unmount failed: %s\n", strerror(rv->au_errno));
+ break;
+ case AMQ_UMNT_FORK:
+ if (rv->au_errno == 0)
+ printf("%s is not mounted\n", fs);
+ else
+ printf("falling back to asynchronous unmount: %s\n",
+ strerror(rv->au_errno));
+ break;
+ case AMQ_UMNT_READ:
+ printf("pipe read error: %s\n", strerror(rv->au_errno));
+ break;
+ case AMQ_UMNT_SERVER:
+ printf("amd server down\n");
+ break;
+ case AMQ_UMNT_SIGNAL:
+ printf("got signal: %d\n", rv->au_signal);
+ break;
+ /*
+ * Omit default so the compiler can check for missing cases.
+ *
+ default:
+ break;
+ */
+ }
+}
+
+
+static int
+amu_sync_umnt_to_retval(amq_sync_umnt *rv)
+{
+ switch (rv->au_etype) {
+ case AMQ_UMNT_FORK:
+ if (rv->au_errno == 0) {
+ /*
+ * We allow this error so that things like:
+ * amq -uu /l/cd0d && eject cd0
+ * will work when /l/cd0d is not mounted.
+ * XXX - We still print an error message.
+ */
+ return 0;
+ }
+ default:
+ return rv->au_etype;
+ }
+}
+
+
+static int
+clnt_failed(CLIENT *clnt, char *server)
+{
+ fprintf(stderr, "%s: ", am_get_progname());
+ clnt_perror(clnt, server);
+ return 1;
+}
+
+
/*
* MAIN
*/
/*
* Parse arguments
*/
- while ((opt_ch = getopt(argc, argv, "Hfh:l:msuvx:D:pP:TUw")) != -1)
+ while ((opt_ch = getopt(argc, argv, "Hfh:l:mqsuvx:D:pP:TUw")) != -1)
switch (opt_ch) {
case 'H':
goto show_usage;
nodefault = 1;
break;
+ case 'q':
+ quiet_flag = 1;
+ nodefault = 1;
+ break;
+
case 's':
stats_flag = 1;
nodefault = 1;
break;
case 'u':
- unmount_flag = 1;
+ unmount_flag++;
nodefault = 1;
break;
if (errs) {
show_usage:
fprintf(stderr, "\
-Usage: %s [-fmpsvwHTU] [-h hostname] [-l log_file|\"syslog\"]\n\
+Usage: %s [-fmpqsvwHTU] [-h hostname] [-l log_file|\"syslog\"]\n\
\t[-x log_options] [-D debug_options]\n\
-\t[-P program_number] [[-u] directory ...]\n",
+\t[-P program_number] [[-u[u]] directory ...]\n",
am_get_progname()
);
exit(1);
if (optind < argc) {
do {
char *fs = argv[optind++];
- if (unmount_flag) {
+ if (unmount_flag > 1) {
+ amq_sync_umnt *sup;
+ /*
+ * Synchronous unmount request
+ */
+ sup = amqproc_sync_umnt_1(&fs, clnt);
+ if (sup) {
+ if (quiet_flag == 0)
+ print_umnt_error(sup, fs);
+ errs = amu_sync_umnt_to_retval(sup);
+ } else {
+ errs = clnt_failed(clnt, server);
+ }
+ } else if (unmount_flag) {
/*
* Unmount request
*/
}
xdr_pri_free((XDRPROC_T_TYPE) xdr_amq_mount_tree_p, (caddr_t) mtp);
} else {
- fprintf(stderr, "%s: ", am_get_progname());
- clnt_perror(clnt, server);
- errs = 1;
+ errs = clnt_failed(clnt, server);
}
}
} while (optind < argc);
if (ms) {
show_ms(ms);
} else {
- fprintf(stderr, "%s: ", am_get_progname());
- clnt_perror(clnt, server);
- errs = 1;
+ errs = clnt_failed(clnt, server);
}
} else if (!nodefault) {
}
} else {
- fprintf(stderr, "%s: ", am_get_progname());
- clnt_perror(clnt, server);
- errs = 1;
+ errs = clnt_failed(clnt, server);
}
}
exit(errs);
extern voidp amqproc_null_1(voidp argp, CLIENT *rqstp);
extern amq_mount_tree_p *amqproc_mnttree_1(amq_string *argp, CLIENT *rqstp);
extern voidp amqproc_umnt_1(amq_string *argp, CLIENT *rqstp);
+extern amq_sync_umnt *amqproc_sync_umnt_1(amq_string *argp, CLIENT *rqstp);
extern amq_mount_stats *amqproc_stats_1(voidp argp, CLIENT *rqstp);
extern amq_mount_tree_list *amqproc_export_1(voidp argp, CLIENT *rqstp);
extern int *amqproc_setopt_1(amq_setopt *argp, CLIENT *rqstp);
}
+amq_sync_umnt *
+amqproc_sync_umnt_1(amq_string *argp, CLIENT *clnt)
+{
+ static amq_sync_umnt res;
+ enum clnt_stat rv;
+
+ memset((char *) &res, 0, sizeof(res));
+ if ((rv = clnt_call(clnt, AMQPROC_SYNC_UMNT,
+ (XDRPROC_T_TYPE) xdr_amq_string, (SVC_IN_ARG_TYPE) argp,
+ (XDRPROC_T_TYPE) xdr_amq_sync_umnt, &res,
+ TIMEOUT)) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return &res;
+}
+
+
amq_mount_stats *
amqproc_stats_1(voidp argp, CLIENT *clnt)
{
* Amq -m option:: Obtaining mount statistics.
* Amq -p option:: Getting Amd's process ID.
* Amq -P option:: Contacting alternate Amd processes.
+* Amq -q option:: Suppress synchronous unmounting errors.
* Amq -s option:: Obtaining global statistics.
* Amq -T option:: Use TCP transport.
* Amq -U option:: Use UDP transport.
used in the @file{ctl-amd} script.
@c ----------------------------------------------------------------
-@node Amq -P option, Amq -s option, Amq -p option, Controlling Amd
+@node Amq -P option, Amq -q option, Amq -p option, Controlling Amd
@comment node-name, next, previous, up
@subsection @i{Amq} @code{-P} option
@cindex Multiple Amd processes
@end example
@c ----------------------------------------------------------------
-@node Amq -s option, Amq -T option, Amq -P option, Controlling Amd
+@node Amq -q option, Amq -s option, Amq -P option, Controlling Amd
+@comment node-name, next, previous, up
+@subsection @i{Amq} @code{-q} option
+@cindex Unmounting a filesystem
+
+Suppress any error messages produced when a synchronous unmount fails.
+See @ref{Amq -u option}.
+
+@c ----------------------------------------------------------------
+@node Amq -s option, Amq -T option, Amq -q option, Controlling Amd
@comment node-name, next, previous, up
@subsection @i{Amq} @code{-s} option
@cindex Global statistics
@cindex Forcing filesystem to time out
@cindex Unmounting a filesystem
-The @code{-u} option causes the time-to-live interval of the named mount
-points to be expired, thus causing an unmount attempt. This is the only
-safe way to unmount an automounted filesystem. It is not possible to
-unmount a filesystem which has been mounted with the @samp{nounmount}
-flag.
+The @code{-u} option causes the time-to-live interval of the named
+mount points to be expired, thus causing an unmount attempt. This is
+the only safe way to unmount an automounted filesystem. If @code{-u}
+is repeated, then @i{Amd} will attempt to unmount the filesystem
+synchronously. This makes things like
+
+@example
+amq -uu /t/cd0d && eject cd0
+@end example
+
+@noindent
+work as expected. Any error messages this might produce can be
+suppressed with the @code{-q} option. See @ref{Amq -q option}.
@c The @code{-H} option informs @i{Amd} that the specified mount point
@c has hung - as if its keepalive timer had expired.
#define AMQ_VERSION ((u_long)1)
#define AMQPROC_NULL ((u_long)0)
#define AMQPROC_MNTTREE ((u_long)1)
-#define AMQPROC_UMNT ((u_long)2)
+#define AMQPROC_UMNT ((u_long)2) /* asynchronous unmount */
#define AMQPROC_STATS ((u_long)3)
#define AMQPROC_EXPORT ((u_long)4)
#define AMQPROC_SETOPT ((u_long)5)
#define AMQPROC_GETVERS ((u_long)8)
#define AMQPROC_GETPID ((u_long)9)
#define AMQPROC_PAWD ((u_long)10)
+#define AMQPROC_SYNC_UMNT ((u_long)11) /* synchronous unmount */
/*
* TYPEDEFS
typedef struct amq_mount_stats amq_mount_stats;
typedef struct amq_mount_tree amq_mount_tree;
typedef struct amq_setopt amq_setopt;
+typedef struct amq_sync_umnt amq_sync_umnt;
typedef amq_mount_tree *amq_mount_tree_p;
/*
int as_uerr;
};
+typedef enum {
+ AMQ_UMNT_OK = 0, /* must be zero! */
+ AMQ_UMNT_FAILED = 1, /* unmount failed */
+ AMQ_UMNT_FORK = 2, /* fork failed */
+ AMQ_UMNT_READ = 3, /* pipe read failed */
+ AMQ_UMNT_SERVER = 4, /* server down */
+ AMQ_UMNT_SIGNAL = 5 /* received signal */
+} au_etype;
+
+struct amq_sync_umnt {
+ au_etype au_etype; /* error type */
+ int au_errno; /* error number */
+ int au_signal; /* signal received */
+};
+
enum amq_opt {
AMOPT_DEBUG = 0,
AMOPT_LOGFILE = 1,
extern bool_t xdr_amq_mount_tree_p(XDR *xdrs, amq_mount_tree_p *objp);
extern bool_t xdr_amq_opt(XDR *xdrs, amq_opt *objp);
extern bool_t xdr_amq_setopt(XDR *xdrs, amq_setopt *objp);
+extern bool_t xdr_amq_sync_umnt(XDR *xdrs, amq_sync_umnt *objp);
extern bool_t xdr_pri_free(XDRPROC_T_TYPE xdr_args, caddr_t args_ptr);
extern bool_t xdr_time_type(XDR *xdrs, time_type *objp);
}
return (TRUE);
}
+
+
+bool_t
+xdr_amq_sync_umnt(XDR *xdrs, amq_sync_umnt *objp)
+{
+
+ if (!xdr_opaque(xdrs, (char *) objp, sizeof(*objp))) {
+ return (FALSE);
+ }
+ return (TRUE);
+}