[comp.sys.hp] NFS mounts - hard versus soft - info. wanted

dave8@anduin.cs.liverpool.ac.uk (08/21/90)

I'm sure this subject must have been raised previously, and I apologise
if it has been brought up very recently, but ... I am looking for
information regarding the advantages and drawbacks of hard versus soft
NFS mounts, in particular, on HP 9000 series machines runnning HP-UX 7.0.

Up to now, we have been using NFS hard mounts, mainly because of concern
that filestore security would be compromised by the use of soft mounts.

However, we are frustrated by situations where a cluster server goes down,
and the workstations on another cluster server hang because the PATH
environment variable on these includes a directory residing on a
partition being exported from the machine that has gone down. We are
considering using soft mounts with an increased value for "retrans".
Altering "retrans" to 8, would mean, I believe, that the machine will try
for about 0.7 * ( 1 + 2 + 4 + 8 + .. 2^7 ) = 180 secs. to carry out the
mount before abandoning the attempt.

The relevant manuals do not seem to provide any guidelines on this.

Dave Sherratt. ....   dave8@uk.ac.liv.cs.and

rvdp@cs.vu.nl (Ronald van der Pol) (08/21/90)

dave8@anduin.cs.liverpool.ac.uk writes:

|information regarding the advantages and drawbacks of hard versus soft
|NFS mounts, in particular, on HP 9000 series machines runnning HP-UX 7.0.
	For filesystems mounted rw use hard mounting or you may lose 
	files (if the connection is lost while the client is writing to 
	the server). Consider soft mounting for filesystems mounted ro.

--
		Ronald van der Pol  <rvdp@cs.vu.nl>

richard@aiai.ed.ac.uk (Richard Tobin) (08/21/90)

In article <1990Aug20.204546.15101@anduin.cs.liverpool.ac.uk> dave8@anduin.cs.liverpool.ac.uk writes:
>However, we are frustrated by situations where a cluster server goes down,
>and the workstations on another cluster server hang because the PATH
>environment variable on these includes a directory residing on a
>partition being exported from the machine that has gone down. 

One way to deal with this is to mount the filesystems in some
obscure place, and make symbolic links to them.  You can then remove
the links when the server goes down.

Of course, this doesn't work if you don't have symbolic links.

You should also mount filesystems from different machines in different
directories, so that "pwd" doesn't hang.

You can have a program maintain the links automatically - here's one
I use.  It may need changing for HPs.

-- Richard

/*
 * nfslink [-i interval] [-t timeout] host name mountpt [name mountpt ...]
 *
 * maintain links to mounted file systems, removing them if the
 * remote machine isn't responding.
 *
 * Copyright Richard Tobin / AIAI 1989
 * 
 * May be freely redistributed if this whole notice remains intact.
 */

#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <sys/time.h>
#include <rpc/rpc.h>
#include <rpc/clnt.h>
#include <nfs/nfs.h>
#include <setjmp.h>
#include <sys/stat.h>
#include <netdb.h>
#include <sys/socket.h>

main(argc, argv)
int argc;
char **argv;
{
    int c, interval = 20, timeout = 5, firsttime = 1;
    extern char *optarg;
    extern int optind, opterr;

    while((c = getopt(argc, argv, "i:t:")) != EOF)
	switch(c)
	{
	  case 'i':
	    interval = atoi(optarg);
	    break;

	  case 't':
	    timeout = atoi(optarg);
	    break;

	  case '?':
	    usage();
	    break;
	}

    if((argc - optind) < 3 || ((argc - optind) & 1) == 0)
	usage();

    while(1)
    {
	if(nfscheck(argv[optind], timeout) == 0)
	    makelinks(&argv[optind+1], firsttime);
	else
	    removelinks(&argv[optind+1], firsttime);

	firsttime = 0;
	sleep(interval);
    }
}

void dodate()
{
    char *tim;
    long *clk;

    time(&clk);
    tim = ctime(&clk);
    tim[24] = '\0';		/* lose the linefeed */

    printf("nfslink: %s: ", tim);
}

makelinks(links, verbose)
char **links;
int verbose;
{
    struct stat namestat;
    
    while(*links)
    {
	char *name = *links++;
	char *mountpt = *links++;

	if(lstat(name, &namestat) == -1)
	{
	    if(errno == ENOENT)
	    {
		if(symlink(mountpt, name) == -1)
		{
		    perror("nfslink: symlink");
		    fatal("can't link %s to %s\n", name, mountpt);
		}
		dodate();
		printf("linked %s to %s\n", name, mountpt);
		fflush(stdout);
		continue;
	    }
	    else
	    {
		perror("nfslink: lstat");
		fatal("can't lstat %s\n", name, 0);
	    }
	}

	if((namestat.st_mode & S_IFMT) == S_IFLNK)
	{
	    if(pointsto(name, mountpt))
	    {
		if(verbose)
		{
		    dodate();
		    printf("%s is already linked to %s\n",
			   name, mountpt);
		    fflush(stdout);
		}
	    }
	    else
	    {
		fatal("%s is a link, but not to %s\n", name, mountpt);
	    }
	}
	else
	{
	    fatal("%s exists, but is not a symbolic link\n", name, 0);
	}
    }
}

removelinks(links, verbose)
char **links;
int verbose;
{
    struct stat namestat;
    
    while(*links)
    {
	char *name = *links++;
	char *mountpt = *links++;

	if(lstat(name, &namestat) == -1)
	{
	    if(errno == ENOENT)
	    {
		if(verbose)
		{
		    dodate();
		    printf("link from %s to %s is already removed\n",
			   name, mountpt);
		    fflush(stdout);
		}
		continue;
	    }
	    else
	    {
		perror("nfslink: lstat");
		fatal("can't lstat %s\n", name, 0);
	    }
	}

	if((namestat.st_mode & S_IFMT) == S_IFLNK)
	{
	    if(pointsto(name, mountpt))
	    {
		if(unlink(name) == -1)
		{
		    perror("nfslink: unlink");
		    fatal("can't remove link from %s to %s\n",
			  name, mountpt);
		}
		dodate();
		printf("removed link from %s to %s\n",
		       name, mountpt);
		fflush(stdout);
	    }
	    else
	    {
		fatal("%s is a link, but not to %s\n", name, mountpt);
	    }
	}
	else
	{
	    fatal("%s exists, but is not a symbolic link\n", name, 0);
	}
    }
}

int pointsto(name, target)
char *name, *target;
{
    /* We don't use stat lest it hang, so it's not quite right */

    char buf[200];
    int len;

    len = readlink(name, buf, sizeof(buf)-1);
    if(len == -1)
    {
	perror("nfslink: readlink");
	fatal("can't read link %s\n", name, 0);
    }

    buf[len] = '\0';
    return strcmp(buf, target) == 0;
}

fatal(fmt, arg1, arg2)
char *fmt, *arg1, *arg2;
{
    fprintf(stderr, "nfslink: fatal error: ");
    fprintf(stderr, fmt, arg1, arg2);
    exit(1);
}

usage()
{
    fprintf(stderr, "usage: nfslink [-i interval] [-t timeout] host name mountpt [name mountpt ...]\n");
    exit(2);
}

int nfscheck(host, timeout)
char *host;
int timeout;
{
    int stat, sock= RPC_ANYSOCK;
    struct hostent *server;
    struct sockaddr_in sin;
    CLIENT *client;
    struct timeval try, total;

    server = gethostbyname(host);
    if(!server)
    {
	fprintf(stderr, "nfslink: unknown host %s\n", host);
	return -1;
    }

    bcopy(server->h_addr, &sin.sin_addr, server->h_length);
    sin.sin_family = AF_INET;
    sin.sin_port = 2049;	/* avoid calling portmapper */

    try.tv_sec = 1;
    try.tv_usec = 0;

    client = clntudp_create(&sin, NFS_PROGRAM, NFS_VERSION,
			    try, &sock);
    if(!client)
	return -1;

    total.tv_sec = timeout;
    total.tv_usec = 0;

    stat = clnt_call(client, RFS_NULL, xdr_void, 0, xdr_void, 0, total);

    clnt_destroy(client);

    if(stat != RPC_SUCCESS)
	return -1;

    return 0;
}


-- 
Richard Tobin,                       JANET: R.Tobin@uk.ac.ed             
AI Applications Institute,           ARPA:  R.Tobin%uk.ac.ed@nsfnet-relay.ac.uk
Edinburgh University.                UUCP:  ...!ukc!ed.ac.uk!R.Tobin