Table of Contents
Unix systems have long tradition of using lock files to gain exclusive access to resources. Similarly, autofs kernel module has the capability to block processes in case mounting NFS exports get delayed. Combining these two features for Autodir results in amazing possibilities that this document intend to explain.
Though intended originally for recovery, but this doc will explain other possibilities which are useful in other circumstances.
![]() | Note |
|---|---|
Before going to details, I assume having knowledge of basic concepts about Autodir and its configuration. | |
When a process try to access any directory managed by Autodir, first Autodir creates shared lock for the directory. Once shared lock file creation is successful, it follows usual course of making it available to the process.
But what if shared lock creation is delayed because someone else already held exclusive lock on it?
For example, if a recovery program already held an exclusive lock on that directory, Autodir blocks all processes from accessing it until recovery program release that lock.
But if any process which does not wish to be blocked by autofs kernel module, it can try to create shared lock, before using Autodir directory. If shared lock creation is successful and it is not released until Autodir directory is accessed by the process, it is guaranteed it will not be blocked.
Once process access Autodir directory, it can release the shared lock safely.
Obviously, this is for recovery programs.
In another case, If you do not want to start backup by Autodir but want to do scheduled backups like, for example, weekly backups, before starting backup on a real directory, create exclusive lock file and start backup on real directory -- refer to Autodir HOWTO for real directory definition. But be clear about the possibility that processes could be blocked by autofs for the moment backup is run.
The default behavior of Autodir is to kill any backup program launched through it whenever directory is to be made available. But some traditional backup programs may not be able to handle this interruptions gracefully without side effects. In this case backup process can choose to create backup lock file and start operating and remove lock file after finishing it. But again chances are there that process which require the directory could be blocked until backup does not terminate.
For each backup lock created and held by Autodir, an open file descriptor is kept open until lock file is removed. If there are 1000 directories are active at any time, it means 1000 open files.
If any process is blocked by autofs kernel module because of backup locks, make sure this does not cause unexpected side effects to this process. Otherwise add code so that it can detect possible blocking through shared lock creation.
There are two options for backup locks.
This is the main option which requests Autodir to create shared backup locks.
Optional, but to specify lock directory to bypass the default value.
Here is the example code to be used by recovery and backup programs.
For creating exclusive locks:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
/*
* name: name of the directory for which lockfile to be created
* lockdir: base directory for creating lock files in it
* strpid: pid of the process creating lock file in string format
* spidlen: length of the string contained in strpid
*
* Return -1 if failed to create or else lockfile fd -- if successful.
*
*/
int lockfile_create( const char *name, const char *lockdir,
const char *strpid, int spidlen )
{
int fd = -1;
int i;
char path[ PATH_MAX + 1 ];
struct flock lk;
struct stat st;
if( ! name || ! *name )
{
fprintf( stderr, "lockfile_create: invalid name\n" );
return -1;
}
snprintf( path, sizeof(path), "%s/%s.lock", lockdir, name );
/*get exclusive lock and lock whole file*/
lk.l_type = F_WRLCK;
lk.l_start = 0;
lk.l_whence = SEEK_SET;
lk.l_len = 0;
/*loop until we get rid of dead files*/
for( i = 0 ; i < 10 ; i++ )
{
if( ( fd = open( path, O_RDWR | O_CREAT, 0644 ) ) == -1 )
{
fprintf( stderr, "open %s: %s\n", path,
strerror( errno ) );
return -1;
}
/*We get blocked here*/
if( fcntl( fd, F_SETLKW, &lk ) == -1 )
{
fprintf( stderr, "fcntl F_SETLKW %s: %s\n",
path, strerror( errno ) );
close( fd );
return -1;
}
if( fstat( fd, &st ) )
{
fprintf( stderr, "fstat %s: %s\n", path,
strerror( errno ) );
close( fd );
return -1;
}
/*not dead file?*/
if( st.st_nlink )
break;
close(fd);
}
/*We do not operate on dead file whose hard link count is zero*/
if( i >= 10 )
{
fprintf( stderr, "Giving up on dead file %s\n", path );
return -1;
}
if( write( fd, strpid, spidlen ) == -1 )
{
fprintf( stderr, "write %s: %s\n", path,
strerror( errno ) );
unlink( path );
close( fd );
return -1;
}
return fd;
}
For removing exclusive locks.
/*
* lock_file: path to the lock file.
* lock_fd: lock file descriptor
*
*/
static void lockfile_remove( const char *lock_file, int lock_fd )
{
struct flock lk;
/*unlock whole file*/
lk.l_type = F_WRLCK;
lk.l_start = 0;
lk.l_whence = SEEK_SET;
lk.l_len = 0;
if( unlink( lock_file ) == -1 )
fprintf( stderr, "unlink %s: %s\n", lock_file,
strerror( errno ) );
if( fcntl( lock_fd, F_UNLCK, &lk ) == -1 )
fprintf( stderr, "fcntl F_UNLCK: %s: %s\n", lock_file,
strerror( errno ) );
close( lock_fd );
}
This document, Autodir and backup locks, is copyrighted (c) 2005 by Venkata Ramana Enaganti. This work is licensed under the Creative Commons Attribution License. To view a copy of this license, visit http://creativecommons.org/licenses/by/2.0/ or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.