* $Id: afs_ops.c,v 5.2 90/06/23 22:19:14 jsp Rel $
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Jan-Simon Pendry at Imperial College, London.
* Redistribution and use in source and binary forms are permitted provided
* that: (1) source distributions retain this entire copyright notice and
* comment, and (2) distributions including binaries display the following
* acknowledgement: ``This product includes software developed by the
* University of California, Berkeley and its contributors'' in the
* documentation or other materials provided with the distribution and in
* all advertising materials mentioning features or use of this software.
* Neither the name of the University nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* @(#)afs_ops.c 5.1 (Berkeley) 6/29/90
typedef nfs_fh fhandle_t
;
* Interval between forced retries of a mount.
* AFS needs nothing in particular.
plog(XLOG_USER
, "auto: no mount point named (rfs:=)");
plog(XLOG_USER
, "auto: no map named (fs:=)");
* Swap round fs:= and rfs:= options
fo
->opt_rfs
= fo
->opt_fs
;
* fs_mtab turns out to be the name of the mount map
fo
->fs_mtab
= strealloc(fo
->fs_mtab
, fo
->opt_rfs
? fo
->opt_rfs
: ".");
* Fill in attribute fields
mf
->mf_fattr
.type
= NFDIR
;
mf
->mf_fattr
.mode
= NFSMODE_DIR
| 0555;
* Mount the an automounter directory.
* The automounter is connected into the system
* as a user-level NFS server. mount_afs constructs
* the necessary NFS parameters to be given to the
* kernel so that it will talk back to us.
static int mount_afs(dir
, fs_name
, opts
)
struct nfs_args nfs_args
;
extern nfs_fh
*root_fh();
char fs_hostname
[MAXHOSTNAMELEN
+MAXPATHLEN
+1];
MTYPE_TYPE type
= MOUNT_TYPE_NFS
;
bzero((voidp
) &nfs_args
, sizeof(nfs_args
)); /* Paranoid */
mnt
.mnt_fsname
= fs_name
;
mnt
.mnt_type
= MNTTYPE_AUTO
;
retry
= hasmntval(&mnt
, "retry");
* get fhandle of remote path for automount point
plog(XLOG_FATAL
, "Can't find root file handle for %s", fs_name
);
NFS_FH_DREF(nfs_args
.fh
, (NFS_FH_TYPE
) fhp
);
* Create sockaddr to point to the local machine. 127.0.0.1
* is not used since that will not work in HP-UX clusters and
* this is no more expensive.
bzero((voidp
) &sin
, sizeof(sin
));
sin
.sin_family
= AF_INET
;
if (port
= hasmntval(&mnt
, "port")) {
sin
.sin_port
= htons(port
);
plog(XLOG_ERROR
, "no port number specified for %s", fs_name
);
NFS_SA_DREF(nfs_args
, &sin
);
* Make a ``hostname'' string for the kernel
sprintf(fs_hostname
, "amd:%d", mypid
);
sprintf(fs_hostname
, "pid%d@%s:%s", mypid
, hostname
, dir
);
#endif /* SHORT_MOUNT_NAME */
nfs_args
.hostname
= fs_hostname
;
nfs_args
.flags
|= NFSMNT_HOSTNAME
;
* Most kernels have a name length restriction.
if (strlen(fs_hostname
) >= HOSTNAMESZ
)
strcpy(fs_hostname
+ HOSTNAMESZ
- 3, "..");
* Parse a subset of the standard nfs options. The
* others are probably irrelevant for this application
if (nfs_args
.timeo
= hasmntval(&mnt
, "timeo"))
nfs_args
.flags
|= NFSMNT_TIMEO
;
if (nfs_args
.retrans
= hasmntval(&mnt
, "retrans"))
nfs_args
.flags
|= NFSMNT_RETRANS
;
if (nfs_args
.biods
= hasmntval(&mnt
, "biods"))
nfs_args
.flags
|= NFSMNT_BIODS
;
#endif /* NFSMNT_BIODS */
#if defined(NFSMNT_ACREGMIN) && defined(NFSMNT_ACREGMAX)
* Don't cache attributes - they are changing under
nfs_args
.acregmin
= nfs_args
.acregmax
= 1;
nfs_args
.flags
|= NFSMNT_ACREGMIN
|NFSMNT_ACREGMAX
;
#endif /* defined(NFSMNT_ACREGMIN) && defined(NFSMNT_ACREGMAX) */
* These two are constructed internally by the calling routine
if (hasmntopt(&mnt
, MNTOPT_SOFT
) != NULL
)
nfs_args
.flags
|= NFSMNT_SOFT
;
if (hasmntopt(&mnt
, MNTOPT_INTR
) != NULL
)
nfs_args
.flags
|= NFSMNT_INT
;
flags
= compute_mount_flags(&mnt
);
nfs_args
.gfs_flags
= flags
;
nfs_args
.flags
|= NFSMNT_RONLY
;
return mount_fs(&mnt
, flags
, (caddr_t
) &nfs_args
, retry
, type
);
* There are two cases to consider...
if (mp
->am_parent
&& mp
->am_parent
->am_parent
) {
* If this am_node has a parent which is not the root node, in
* which case we are supplying a pseudo-directory, in which
* case no action is needed. Pseudo-directories are used to
* provide some structure to the automounted directories instead
* of putting them all in the top-level automount directory.
mp
->am_parent
->am_mnt
->mf_fattr
.nlink
++;
* Info field of . means use parent's info field.
if (mf
->mf_info
[0] == '.' && mf
->mf_info
[1] == '\0')
mf
->mf_info
= strealloc(mf
->mf_info
, mp
->am_parent
->am_mnt
->mf_info
);
* If there is an option prefix then use that else
* If the parent had a prefix then use that with name
* of this node appended else
* Use the name of this node.
* That means if you want no prefix you must say so
if (mf
->mf_fo
->opt_pref
) {
* the prefix specified as an option
mp
->am_pref
= strdup(mf
->mf_fo
->opt_pref
);
* else the parent's prefix
char *ppref
= mp
->am_parent
->am_pref
;
mp
->am_pref
= str3cat((char *) 0, ppref
, mp
->am_name
, "/");
* Otherwise, we are mounting the automounter. In which case
* we need to make sure the mount directory exists, construct
* the mount options and call the mount_afs routine.
* Top-level mount - so make
* sure the mount point exists
error
= mkdirs(mp
->am_path
, 0555);
mp
->am_flags
|= AMF_MKPATH
;
if (stat(mp
->am_path
, &stb
) < 0) {
} else if ((stb
.st_mode
& S_IFMT
) != S_IFDIR
) {
plog(XLOG_WARNING
, "%s is not a directory", mp
->am_path
);
mf
->mf_mount
= strealloc(mf
->mf_mount
, mp
->am_path
);
* Construct some mount options
"%s,%s,%s=%d,%s=%d,%s=%d,%sdirect",
"%s,%s=%d,%s=%d,%s=%d,%sdirect",
MNTOPT_RO
, /* You don't really want this... */
#endif /* AUTOMOUNT_RO */
mf
->mf_ops
== &afs_ops
? "in" : "");
error
= mount_afs(mp
->am_path
, mp
->am_name
, opts
);
plog(XLOG_FATAL
, "mount_afs: %m");
mp
->am_name
= pid_fsname
;
* Build a new map cache for this node, or re-use
* an existing cache for the same map.
if (mf
->mf_fo
->opt_cache
)
cache
= mf
->mf_fo
->opt_cache
;
mf
->mf_private
= (voidp
) mapc_find(mf
->mf_info
, cache
);
mf
->mf_prfree
= mapc_free
;
* Unmount an automount node
static int afs_umount(mp
)
* If this is a pseudo-directory then just adjust the link count
* in the parent, otherwise call the generic unmount routine
} else if (mp
->am_parent
&& mp
->am_parent
->am_parent
) {
--mp
->am_parent
->am_mnt
->mf_fattr
.nlink
;
* The lstat is needed if this mount is type=direct.
* When that happens, the kernel cache gets confused
* between the underlying type (dir) and the mounted
* type (link) and so needs to be re-synced before
* the unmount. This is all because the unmount system
* call follows links and so can't actually unmount
* a link (stupid!). It was noted that doing an ls -ld
* of the mount point to see why things were not working
* actually fixed the problem - so simulate an ls -ld here.
if (lstat(mp
->am_path
, &stb
) < 0) {
dlog("lstat(%s): %m", mp
->am_path
);
error
= UMOUNT_FS(mp
->am_path
);
plog(XLOG_WARNING
, "afs_unmount retrying %s in 1s", mp
->am_path
);
* Unmount an automount node
static void afs_umounted(mp
)
* If this is a pseudo-directory then just adjust the link count
* in the parent, otherwise call the generic unmount routine
if (mp
->am_parent
&& mp
->am_parent
->am_parent
)
--mp
->am_parent
->am_mnt
->mf_fattr
.nlink
;
* Mounting a file system may take a significant period of time. The
* problem is that if this is done in the main process thread then
* the entire automounter could be blocked, possibly hanging lots of
* processes on the system. Instead we use a continuation scheme to
* allow mounts to be attempted in a sub-process. When the sub-process
* exits we pick up the exit status (by convention a UN*X error number)
* and continue in a notifier. The notifier gets handed a data structure
* and can then determine whether the mount was successful or not. If
* not, it updates the data structure and tries again until there are no
* more ways to try the mount, or some other permanent error occurs.
* In the mean time no RPC reply is sent, even after the mount is succesful.
* We rely on the RPC retry mechanism to resend the lookup request which
char **ivec
; /* Current mount info */
am_node
*mp
; /* Node we are trying to mount */
char *info
; /* Info string */
char **xivec
; /* Saved strsplit vector */
char *opts
; /* Mount options */
am_opts fs_opts
; /* Filesystem options */
char *def_opts
; /* Default options */
int retry
; /* Try again? */
int tried
; /* Have we tried any yet? */
time_t start
; /* Time we started this mount */
int callout
; /* Callout identifier */
* Discard an old continuation
static void free_continuation(cp
)
free((voidp
) cp
->def_opts
);
static int afs_bgmount
P((struct continuation
*, int));
* Discard the underlying mount point and replace
* with a reference to an error filesystem.
static void assign_error_mntfs(mp
)
* Save the old error code
int error
= mp
->am_error
;
* Discard the old filesystem
* Allocate a new error reference
mp
->am_mnt
= new_mntfs();
* Put back the error code
mp
->am_mnt
->mf_error
= error
;
mp
->am_mnt
->mf_flags
|= MFF_ERROR
;
* Zero the error in the mount point
* The continuation function. This is called by
* the task notifier when a background mount attempt
static void afs_cont(rc
, term
, closure
)
struct continuation
*cp
= (struct continuation
*) closure
;
mntfs
*mf
= cp
->mp
->am_mnt
;
* Definitely not trying to mount at the moment
mf
->mf_flags
&= ~MFF_MOUNTING
;
* While we are mounting - try to avoid race conditions
* Wakeup anything waiting for this mount
* Check for termination signal or exit status...
* Not sure what to do for an error code.
mf
->mf_error
= EIO
; /* XXX ? */
mf
->mf_flags
|= MFF_ERROR
;
plog(XLOG_ERROR
, "mount for %s got signal %d", cp
->mp
->am_path
, term
);
* Check for exit status...
mf
->mf_flags
|= MFF_ERROR
;
plog(XLOG_ERROR
, "%s: mount (afs_cont): %m", cp
->mp
->am_path
);
* If we get here then that attempt didn't work, so
* move the info vector pointer along by one and
* call the background mount routine again
(void) afs_bgmount(cp
, 0);
assign_error_mntfs(cp
->mp
);
static void afs_retry(rc
, term
, closure
)
struct continuation
*cp
= (struct continuation
*) closure
;
dlog("Commencing retry for mount of %s", cp
->mp
->am_path
);
if ((cp
->start
+ ALLOWED_MOUNT_TIME
) < clocktime()) {
* The entire mount has timed out.
* Set the error code and skip past
* all the info vectors so that
* afs_bgmount will not have any more
* ways to try the mount, so causing
plog(XLOG_INFO
, "mount of \"%s\" has timed out", cp
->mp
->am_path
);
(void) afs_bgmount(cp
, error
);
* Try to mount a file system. Can be called
* directly or in a sub-process by run_task
dlog("afs call to mount_node failed: %m");
* Pick a file system to try mounting and
* do that in the background if necessary
if it is new -defaults then
if a location has been tried then
discard previous mount location if required
find matching mounted filesystem
this_error = No such file or directory
if the filesystem failed to be mounted then
this_error = error from filesystem
elif the filesystem is mounting or unmounting then
elif the fileserver is down then
elif the filesystem is already mounted
if no error on this mount then
this_error = initialise mount point
if no error on this mount and mount is delayed then
if no error on this mount then
make mount point if required
if no error on this mount then
if mount in background then
this_error = mount in foreground
if an error occured on this mount then
save error in mount point
static int afs_bgmount(cp
, mpe
)
mntfs
*mf
= cp
->mp
->am_mnt
; /* Current mntfs */
mntfs
*mf_retry
= 0; /* First mntfs which needed retrying */
int this_error
= -1; /* Per-mount error */
* Try to mount each location.
* hard_error == 0 indicates something was mounted.
* hard_error > 0 indicates everything failed with a hard error
* hard_error < 0 indicates nothing could be mounted now
for (; this_error
&& *cp
->ivec
; cp
->ivec
++) {
if (cp
->opts
&& *cp
->opts
)
cp
->def_opts
= str3cat(cp
->def_opts
, cp
->opts
, ";", *cp
->ivec
+1);
cp
->def_opts
= strealloc(cp
->def_opts
, *cp
->ivec
+1);
dlog("Setting def_opts to \"%s\"", cp
->def_opts
);
* If a mount has been attempted, and we find
* a cut then don't try any more locations.
if (strcmp(*cp
->ivec
, "/") == 0 || strcmp(*cp
->ivec
, "||") == 0) {
dlog("Cut: not trying any more locations for %s",
* By default, you only get this bit on SunOS4.
* If you want this anyway, then define SUNOS4_COMPAT
* in the relevant "os-blah.h" file.
* We make the observation that if the local key line contains
* no '=' signs then either it is sick, or it is a SunOS4-style
* "host:fs[:link]" line. In the latter case the am_opts field
* is also assumed to be in old-style, so you can't mix & match.
* You can use ${} expansions for the fs and link bits though...
* Actually, this doesn't really cover all the possibilities for
* the latest SunOS automounter and it is debatable whether there
* is any point bothering.
if (strchr(*cp
->ivec
, '=') == 0)
p
= sunos4_match(&cp
->fs_opts
, *cp
->ivec
, cp
->def_opts
, mp
->am_path
, cp
->key
, mp
->am_parent
->am_mnt
->mf_info
);
#endif /* SUNOS4_COMPAT */
p
= ops_match(&cp
->fs_opts
, *cp
->ivec
, cp
->def_opts
, mp
->am_path
, cp
->key
, mp
->am_parent
->am_mnt
->mf_info
);
* Find a mounted filesystem for this node.
mp
->am_mnt
= mf
= realloc_mntfs(mf
, p
, &cp
->fs_opts
, cp
->fs_opts
.opt_fs
,
cp
->fs_opts
.fs_mtab
, cp
->opts
);
dlog("Got a hit with %s", p
->fs_type
);
* Note whether this is a real mount attempt
plog(XLOG_MAP
, "Map entry %s for %s failed to match", *cp
->ivec
, mp
->am_path
);
if (cp
->fs_opts
.fs_mtab
) {
plog(XLOG_MAP
, "Trying mount of %s on %s fstype %s",
cp
->fs_opts
.fs_mtab
, mp
->am_path
, p
->fs_type
);
link_dir
= mf
->mf_fo
->opt_sublink
;
if (link_dir
&& *link_dir
) {
mp
->am_link
= strdup(link_dir
);
mp
->am_link
= str3cat((char *) 0,
mf
->mf_fo
->opt_fs
, "/", link_dir
);
this_error
= mf
->mf_error
;
} else if (mf
->mf_flags
& (MFF_MOUNTING
|MFF_UNMOUNTING
)) {
* Still mounting - retry later
dlog("Duplicate pending mount fstype %s", p
->fs_type
);
} else if (FSRV_ISDOWN(mf
->mf_server
)) {
* Would just mount from the same place
* as a hung mount - so give up
dlog("%s is already hung - giving up", mf
->mf_mount
);
} else if (mf
->mf_flags
& MFF_MOUNTED
) {
dlog("duplicate mount of \"%s\" ...", mf
->mf_info
);
* Will usually need to play around with the mount nodes
* file attribute structure. This must be done here.
* Fill in attribute fields
mf
->mf_fattr
.type
= NFLNK
;
mf
->mf_fattr
.mode
= NFSMODE_LNK
| 0777;
mf
->mf_fattr
.size
= MAXPATHLEN
/ 4; /* Conservative */
mf
->mf_fattr
.fileid
= mp
->am_gen
;
this_error
= (*p
->fs_init
)(mf
);
if (!this_error
&& mf
->mf_fo
->opt_delay
) {
* If there is a delay timer on the mount
* then don't try to mount if the timer
int i
= atoi(mf
->mf_fo
->opt_delay
);
if (i
> 0 && (cp
->start
+ i
) < clocktime()) {
dlog("Mount of %s delayed by %ds", mf
->mf_mount
, i
);
if (this_error
< 0 && !dont_retry
) {
mf_retry
= dup_mntfs(mf
);
* If the directory is not yet made and
* it needs to be made, then make it!
if (!(mf
->mf_flags
& MFF_MKMNT
) &&
p
->fs_flags
& FS_MKMNT
) {
this_error
= mkdirs(mf
->mf_mount
, 0555);
mf
->mf_flags
|= MFF_MKMNT
;
if (p
->fs_flags
& FS_MBACKGROUND
) {
mf
->mf_flags
|= MFF_MOUNTING
; /*XXX*/
dlog("backgrounding mount of \"%s\"", mf
->mf_info
);
run_task(try_mount
, (voidp
) mp
, afs_cont
, (voidp
) cp
);
if (mf_retry
) free_mntfs(mf_retry
);
dlog("foreground mount of \"%s\" ...", mf
->mf_info
);
this_error
= try_mount(mp
);
mf
->mf_error
= this_error
;
mf
->mf_flags
|= MFF_ERROR
;
* Wakeup anything waiting for this mount
if (this_error
&& cp
->retry
) {
mf
= cp
->mp
->am_mnt
= mf_retry
;
* Not retrying again (so far)
* Start at the beginning.
* Rewind the location vector and
* reset the default options.
cp
->def_opts
= strealloc(cp
->def_opts
, cp
->opts
);
* Arrange that afs_bgmount is called
* after anything else happens.
dlog("Arranging to retry mount of %s", cp
->mp
->am_path
);
sched_task(afs_retry
, (voidp
) cp
, (voidp
) mf
);
cp
->callout
= timeout(RETRY_INTERVAL
, wakeup
, (voidp
) mf
);
cp
->mp
->am_ttl
= clocktime() + RETRY_INTERVAL
;
* Not done yet - so don't return anything
* Discard handle on duff filesystem.
* This should never happen since it
* should be caught by the case above.
plog(XLOG_ERROR
, "discarding a retry mntfs for %s", mf_retry
->mf_mount
);
if (hard_error
< 0 || !this_error
)
* If we get here, then either the mount succeeded or
* there is no more mount information available.
if (hard_error
< 0 && mp_error
)
hard_error
= cp
->mp
->am_error
= mp_error
;
* Set a small(ish) timeout on an error node if
* the error was not a time out.
* Make sure that the error value in the mntfs has a
mf
->mf_error
= hard_error
;
mf
->mf_flags
|= MFF_ERROR
;
* In any case we don't need the continuation any more
* Automount interface to RPC lookup routine
static am_node
*afs_lookuppn(mp
, fname
, error_return
, op
)
#define ereturn(x) { *error_return = x; return 0; }
* Find the corresponding entry and return
* the file handle for it.
am_node
*ap
, *new_mp
, *ap_hung
;
char *info
; /* Mount info - where to get the file system */
char **ivec
, **xivec
; /* Split version of info */
char *opts
; /* Mount options */
int error
= 0; /* Error so far */
char path_name
[MAXPATHLEN
]; /* General path name buffer */
char *pfname
; /* Path for database lookup */
struct continuation
*cp
; /* Continuation structure if we need to mount */
int in_progress
= 0; /* # of (un)mount in progress */
* If the server is shutting down
* then don't return information
if (amd_state
== Finishing
) {
dlog("%s/%s mount ignored - going down",
* Handle special case of "." and ".."
return mp
; /* "." is the current node */
if (fname
[1] == '.' && fname
[2] == '\0') {
dlog(".. in %s gives %s", mp
->am_path
, mp
->am_parent
->am_path
);
return mp
->am_parent
; /* ".." is the parent node */
* Check for valid key name.
* If it is invalid then pretend it doesn't exist.
plog(XLOG_WARNING
, "Key \"%s\" contains a disallowed character", fname
);
* fname is now a private copy.
fname
= expand_key(fname
);
for (ap_hung
= 0, ap
= mp
->am_child
; ap
; ap
= ap
->am_osib
) {
* Otherwise search children of this node
if (FSTREQ(ap
->am_name
, fname
)) {
* If the error code is undefined then it must be
if (FSRV_ISDOWN(mf
->mf_server
)) {
* If there was a previous error with this node
* then return that error code.
if (mf
->mf_flags
& MFF_ERROR
) {
if (!(mf
->mf_flags
& MFF_MOUNTED
) /*|| (mf->mf_flags & MFF_UNMOUNTING)*/) {
* If the fs is not mounted or it is unmounting then there
* is a background (un)mount in progress. In this case
* we just drop the RPC request (return nil) and
* wait for a retry, by which time the (un)mount may
dlog("ignoring mount of %s in %s -- in progress",
* Otherwise we have a hit: return the current mount point.
dlog("matched %s in %s", fname
, ap
->am_path
);
dlog("Waiting while %d mount(s) in progress", in_progress
);
* If an error occured then return it.
dlog("Returning error: %m", error
);
* If doing a delete then don't create again!
plog(XLOG_FATAL
, "Unknown op to afs_lookuppn: 0x%x", op
);
* If the server is going down then just return,
* don't try to mount any more file systems
if ((int)amd_state
>= (int)Finishing
) {
dlog("not found - server going down anyway");
* If we get there then this is a reference to an,
* as yet, unknown name so we need to search the mount
sprintf(path_name
, "%s%s", mp
->am_pref
, fname
);
dlog("will search map info in %s to find %s", mf
->mf_info
, pfname
);
* Consult the oracle for some mount information.
* info is malloc'ed and belongs to this routine.
* It ends up being free'd in free_continuation().
* Note that this may return -1 indicating that information
error
= mapc_search((mnt_map
*) mf
->mf_private
, pfname
, &info
);
plog(XLOG_MAP
, "No map entry for %s", pfname
);
dlog("mount info is %s", info
);
* Split info into an argument vector.
* The vector is malloc'ed and belongs to
* this routine. It is free'd in free_continuation()
xivec
= ivec
= strsplit(info
, '\"');
new_mp
= exported_ap_alloc();
dlog("searching for /defaults entry");
if (mapc_search((mnt_map
*) mf
->mf_private
, "/defaults", &dflts
) == 0) {
dlog("/defaults gave %s", dflts
);
rvec
= strsplit(dfl
, '\"');
* Log error if there were other values
dlog("/defaults chopped into %s", dfl
);
plog(XLOG_USER
, "More than a single value for /defaults in %s", mf
->mf_info
);
* Don't need info vector any more
* If there were any values at all...
* Prepend to existing defaults if they exist,
* otherwise just use these defaults.
char *nopts
= (char *) xmalloc(strlen(opts
)+strlen(dfl
)+2);
sprintf(nopts
, "%s;%s", dfl
, opts
);
opts
= strealloc(opts
, dfl
);
* Fill in some other fields,
new_mp
->am_path
= str3cat(new_mp
->am_path
, mp
->am_path
, *fname
== '/' ? "" : "/", fname
);
dlog("setting path to %s", new_mp
->am_path
);
* Take private copy of pfname
* Construct a continuation
cp
= ALLOC(continuation
);
cp
->def_opts
= strdup(opts
);
bzero((voidp
) &cp
->fs_opts
, sizeof(cp
->fs_opts
));
* Try and mount the file system
* If this succeeds immediately (possible
* for a ufs file system) then return
* the attributes, otherwise just
error
= afs_bgmount(cp
, error
);
assign_error_mntfs(cp
->mp
);
* Locate next node in sibling list which is mounted
* and is not an error node.
static am_node
*next_nonerror_node(xp
)
* Bug report (7/12/89) from Rein Tollevik <rein@ifi.uio.no>
* Fixes a race condition when mounting direct automounts.
* Also fixes a problem when doing a readdir on a directory
* containing hung automounts.
(!(mf
= xp
->am_mnt
) || /* No mounted filesystem */
mf
->mf_error
!= 0 || /* There was a mntfs error */
xp
->am_error
!= 0 || /* There was a mount error */
!(mf
->mf_flags
& MFF_MOUNTED
) || /* The fs is not mounted */
(mf
->mf_server
->fs_flags
& FSF_DOWN
)) /* The fs may be down */
static int afs_readdir(mp
, cookie
, dp
, ep
)
unsigned int gen
= *(unsigned int*) cookie
;
* In the default instance (which is used to
* start a search) we return "." and "..".
* This assumes that the count is big enough
* to allow both "." and ".." to be returned in
* a single packet. If it isn't (which would
* be fairly unbelievable) then tough.
xp
= next_nonerror_node(mp
->am_child
);
ep
[0].fileid
= mp
->am_gen
;
ep
[0].nextentry
= &ep
[1];
*(unsigned int *) ep
[0].cookie
= 0;
ep
[1].fileid
= mp
->am_parent
->am_gen
;
ep
[1].fileid
= mp
->am_gen
;
*(unsigned int *) ep
[1].cookie
=
xp
? xp
->am_gen
: ~(unsigned int)0;
if (gen
== ~(unsigned int)0) {
dlog("End of readdir in %s", mp
->am_path
);
while (xp
&& xp
->am_gen
!= gen
)
am_node
*xp_next
= next_nonerror_node(xp
->am_osib
);
*(unsigned int *) ep
->cookie
= xp_next
->am_gen
;
*(unsigned int *) ep
->cookie
= ~(unsigned int)0;
static am_node
*dfs_readlink(mp
, error_return
)
xp
= next_nonerror_node(mp
->am_child
);
xp
= afs_lookuppn(mp
, mp
->am_path
+1, &rc
, VLOOK_CREATE
);
new_ttl(xp
); /* (7/12/89) from Rein Tollevik */
if (amd_state
== Finishing
)
FS_NOTIMEOUT
|FS_UBACKGROUND
|FS_AMQINFO
FS_NOTIMEOUT
|FS_UBACKGROUND
|FS_AMQINFO