Detecting directory changes.

Dave Jones JONESD at er6s1.eng.ohio-state.edu
Mon Mar 3 06:56:59 GMT 2003


I just joined this list, I've been playing with samba to the past few weeks.

In the archives there was discussion of the difficulty of reliably 
invalidating the stat cache when directory updates don't change it's
allocation.  While poking around the VMS source listings for a better
solution, I came across a system routine that looks made to order for this
problem.  If you open the directory file, the function F11X$POSIX_FASTRDSEQNOS
can be used to quickly fetch the header and data sequence numbers stored
in the access lock's value block.  Any change to the contents of the
directory increments the data sequence, even if the header sequence
(file allocation, protection, etc) remains unchanged.

Below is a program that demonstrates the function.  I've tested the program
under Alpha VMS 7.2-1 and 7.3-1, the routine appears to have been introduced 
circa 1993.

------------------------------------------------------------------------------
/*
 * Test for existence of f11x$posix_fastreadseqnos. This function returns
 * the sequence numbers held in the serialization lock for an open
 * directory, allowing you to quickly test for modification:
 *
 *    hdrseq	Incremented when header data changed (e.g. file
 *		grows or shrinks).
 *
 *    dataseq	Incremented when file data changes (e.g. file renamed).
 *
 * Privileges:
 *    Caller must have sysprv and cmkrnl privilege.
 *
 * Linking:
 *    Link the the /sysexe qualifier (sys$system:sys.stb on vax) to resolve
 *    the F11X$POSIX_FASTRDSEQNOS reference.
 *
 * Author:	David Jones
 * Date:	3-MAR-2003
 *			
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stat.h>

#include <fibdef.h>
#include <ssdef.h>
#include <starlet.h>
#include <descrip.h>
#include <iodef.h>

struct seqno_st {
    long hdrseq;			/* header data sequnece */
    long dataseq;			/* file data sequence */
};
/*
 * This function is part of the operating system image, link using
 * the /sysexe[/selective_search] qualifer.
 */
int F11X$POSIX_FASTRDSEQNOS ( short chan, struct seqno_st *seqno );

int main (int argc, char **argv) 
{
    int status;
    struct seqno_st seqno;
    short chan;
    struct stat info;
    static $DESCRIPTOR(devnam_dx,"");
    struct { int length; struct fibdef *fib; } fib_desc;
    struct fibdef fib;
    struct { unsigned short status, count; long devdepend; } iosb;
    char line[80];
    /*
     * Mislinking can cause system crash! do sanity check.
     */
    if ( !F11X$POSIX_FASTRDSEQNOS ) {
	printf ( "Program improperly built, must link /sysexe\n" );
	return SS$_ABORT;
    }
    /*
     * Stat the directory file named on the command line in order to
     * get device name and file id.
     */
    if ( argc < 2 ) {
	printf ( "usage: fast_seqno filename\n" );
	return 1;
    }
    status = stat ( argv[1], &info );
    if ( status != 0 ) {
	printf ( "Failed to stat file '%s'\n", argv[1] );
	return 1;
    }
    /*
     * Assign channel and access file with speical fib$m_seqno that forces
     * XQP to keep an access lock on the file.
     */
    devnam_dx.dsc$a_pointer = info.st_dev;
    devnam_dx.dsc$w_length = strlen ( devnam_dx.dsc$a_pointer );
    status = SYS$ASSIGN ( &devnam_dx, &chan, 0, 0, 0 );
    if ( (status&1) == 0 ) {
	printf ( "Assign to '%s' failed: %d\n", info.st_dev, status );
	return status;
    }

    fib.fib$l_acctl = FIB$M_SEQNO | FIB$M_NORECORD | FIB$M_NOLOCK;
    fib.fib$w_fid[0] = info.st_ino[0];
    fib.fib$w_fid[1] = info.st_ino[1];
    fib.fib$w_fid[2] = info.st_ino[2];

    fib.fib$w_did[0] = fib.fib$w_did[1] = fib.fib$w_did[2] = 0;

    fib_desc.length = 10;		/* minimal FIB */
    fib_desc.fib = &fib;

    status = SYS$QIOW ( 0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb,
	0, 0,
	&fib_desc, 0, 0, 0, 0, 0 );
    if ( (status&1) == 1 ) status = iosb.status;
    if ( (status&1) == 0 ) {
        printf ( "Error in access, status: %d, iosb: %d %d %x\n", status,
		iosb.status, iosb.count, iosb.devdepend );
	return status;
    }
    /*
     * Now enter loop where we fetch sequence numbers every time returnis
     * it.
     */
    printf ( "Each time you hit return, the current sequence numbers will\n");
    printf ( "fetched and displayed.  hit ctrl-Z to exit\n" );
    seqno.hdrseq = 0;
    seqno.dataseq = 0;
    while ( fgets ( line, 79, stdin ) ) {
	/*
	 * XQP function must be called from kernel mode (probably
	 * need pages locked as well).
	 */
	struct {
	    long count;
	    long channel;
	    struct seqno_st *seqno;
        } arglist;

	arglist.count = 2;
	arglist.channel = chan;
	arglist.seqno = &seqno;

	status = SYS$CMKRNL ( F11X$POSIX_FASTRDSEQNOS, &arglist );

	printf ( "status: %d, hdrseq: %d, dataseq: %d\n", status,
		seqno.hdrseq, seqno.dataseq );
    }
    /*
     * Cleanup.
     */
    status = SYS$QIOW ( 0, chan, IO$_DEACCESS, &iosb, 0, 0,
	&fib_desc, 0, 0, 0, 0, 0 );
    if ( (status&1) == 1 ) status = iosb.status;
	
    return status;
}

-----------------------------------------------------------------------------
David L. Jones               |      Phone:    (614) 292-6929
Ohio State University        |      Internet:
140 W. 19th St. Rm. 231a     |               jonesd at er6s1.eng.ohio-state.edu
Columbus, OH 43210           |               vman+ at osu.edu

Disclaimer: I'm looking for marbles all day long.


More information about the samba-vms mailing list