[K42-discussion] Volatile directories and revalidation patch

Patrick Bozeman PEBozeman at lbl.gov
Fri Oct 6 08:23:59 EST 2006


What is the current status of the patch in this thread?

I can't submit my next patch until this has been applied since the  
volatile proc dirs derive from FileInfoVirtFSDirVolatile.


On Sep 20, 2006, at 7:42 PM, Patrick Bozeman wrote:

> This patch probably could have been split into a few pieces, but  
> they are somewhat intertwined.   Let me know if you want it broken  
> up.  The patch provides 3 things:
>
> 1) Provides a FileInfoVirtFSDirVolatile class.  This class is  
> actually a combo of static and dynamic directory functionality.  It  
> has FileInfoVirtFSDirStatic as its base class, so it is possible to  
> add static files and perform lookups on them using the static dir  
> methods.  However, it overrides key methods such as directory  
> enumeration and object lookup.  For such methods, it first calls  
> the static dir method and then a dynamic method implemented by  
> derived classes.  This is of course useful for directories such as / 
> proc that has a mix of static and dynamic content, and for  
> directories like /proc/<pid>/fd that have only dynamic content.
>
> 2) getRecLen was moved from a static function in FileInfoVirtFS.C  
> to a static member function of FileInfoVirtFSDirBase.  This enables  
> derived classes outside of this compilation unit to call it (e.g.  
> the derived classes used in the procfs server.)
>
> 3)  Provides isStale() and shouldRevalidate() methods to the  
> FileInfoVirtFSDir class hierarchy and calls them from  
> ServerFileDirVirtFS  to check and potentially trigger  
> revalidation.   This causes revalidation to occur before a stale  
> object gets used rather than after as was the case before this  
> change.  (And it largely avoids the bug from my previous email.)
>
> People may have stylistic issues with part number 1 of the patch.  
> Let me know what you think.
> diff -ru kitchsrc.orig/lib/libc/fslib/virtfs/FileInfoVirtFS.C  
> kitchsrc/lib/libc/fslib/virtfs/FileInfoVirtFS.C
> --- kitchsrc.orig/lib/libc/fslib/virtfs/FileInfoVirtFS.C	2006-09-14  
> 16:06:16.000000000 -0700
> +++ kitchsrc/lib/libc/fslib/virtfs/FileInfoVirtFS.C	2006-09-20  
> 17:05:54.000000000 -0700
> @@ -276,7 +276,13 @@
>      return locked_lookup(name, namelen, entry);
>  }
>
> -
> +/* static */ uval
> +FileInfoVirtFSDirBase::getRecLen(uval lengthString) {
> +    uval recLen = sizeof(struct direntk42);
> +    recLen += lengthString - sizeof(((direntk42 *)0)->d_name) + 1;
> +    recLen = ALIGN_UP(recLen, sizeof(uval64));
> +    return recLen;
> +}
>
>  /* virtual */ SysStatus
>  FileInfoVirtFSDirStatic::destroy()
> @@ -435,14 +441,6 @@
>      return rc;
>  }
>
> -inline uval
> -getRecLen(uval lengthString) {
> -    uval recLen = sizeof(struct direntk42);
> -    recLen += lengthString - sizeof(((direntk42 *)0)->d_name) + 1;
> -    recLen = ALIGN_UP(recLen, sizeof(uval64));
> -    return recLen;
> -}
> -
>  /* virtual */ SysStatusUval
>  FileInfoVirtFSDirStatic::getDents(uval &cookie, struct direntk42  
> *buf, uval len)
>  {
> @@ -552,3 +550,126 @@
>      err_printf("Shouldn't call this yet: %s\n",__func__);
>      return 0;
>  }
> +
> +/* virtual */ SysStatus
> +FileInfoVirtFSDirVolatile::getStatus(FileLinux::Stat *stat)
> +{
> +    SysStatus rc;
> +    uval nlink;
> +
> +    rc = FileInfoVirtFS::getStatus(stat);
> +    _IF_FAILURE_RET(rc);
> +
> +    nlink = getLinksDynamic();
> +    _IF_FAILURE_RET_VERBOSE(rc);
> +
> +    stat->st_nlink += _SGETUVAL(nlink);
> +    return rc;
> +}
> +
> +/* virtual */ SysStatus
> +FileInfoVirtFSDirVolatile::getFSFileOrServerFile(char *entryName,  
> uval entryLen,
> +						 FSFile **entryInfo, ServerFileRef &ref,
> +						 MultiLinkMgrLock* &mmlock,
> +						 FileLinux::Stat *status)
> +{
> +    SysStatus rc;
> +
> +    rc = FileInfoVirtFSDirStatic::getFSFileOrServerFile(entryName,  
> entryLen,
> +							entryInfo, ref,
> +							mmlock, status);
> +    if (_FAILURE(rc) && _SGENCD(rc) == ENOENT) {
> +	rc = getFSFileOrServerFileDynamic(entryName, entryLen, entryInfo,  
> ref,
> +					  mmlock, status);
> +    }
> +
> +    return rc;
> +}
> +
> +/* virtual */ SysStatusUval
> +FileInfoVirtFSDirVolatile::getDents(uval &cookie, struct direntk42  
> *buf, uval len)
> +{
> +    SysStatus rc;
> +    uval consumed = 0;
> +    struct direntk42 *prevdp = NULL;
> +
> +    // Skip the static session if we left of in dynamic part last  
> time.
> +    if ((cookie & DYNAMIC_FLAG) == 0) {
> +	rc = FileInfoVirtFSDirStatic::getDents(cookie, buf, len);
> +	_IF_FAILURE_RET(rc);
> +	consumed = _SGETUVAL(rc);
> +    }
> +
> +    /*
> +     * If static getDents placed entires in the front of the buffer,
> +     * find the last one so that we can append to its output.
> +     */
> +    if (consumed) {
> +	prevdp = buf;
> +
> +	while (prevdp->d_off != 0) {
> +	    tassertMsg(prevdp->d_off ==
> +		       (__off64_t) (prevdp->d_reclen +
> +				    (uval) prevdp - (uval) buf),
> +		       "buf corrupt\n");
> +
> +	    prevdp = (struct direntk42 *) ((uval) buf + prevdp->d_off);
> +
> +	    tassertMsg((uval) prevdp < (uval) buf + len, "buf overflow\n");
> +	}
> +
> +	tassertMsg((uval) prevdp + prevdp->d_reclen == (uval) buf +  
> consumed,
> +		   "buf consumed inconsistent with dirents\n");
> +
> +	/* advance by the amount consumed by the static getDents */
> +	len -= consumed;
> +	buf = (struct direntk42 *) ((uval) buf + consumed);
> +    }
> +
> +    /*
> +     * If we still have room in the buffer, add the dynamic entries.
> +     */
> +    if (len >= sizeof(struct direntk42)) {
> +	rc = getDentsDynamic(cookie, buf, len, consumed);
> +	_IF_FAILURE_RET(rc);
> +
> +	/* if there are entries at the front of the buffer from
> +	 * FileInfoFSDirStatic::getDents() and we added more
> +	 * in the call to getDentsDynamic, update the last
> +	 * dirent's offset in the static portion of the buffer.
> +	 */
> +	if (prevdp && _SGETUVAL(rc)) {
> +	    tassertMsg(consumed, "?");
> +	    prevdp->d_off = consumed;
> +	}
> +
> +	consumed += _SGETUVAL(rc);
> +    }
> +
> +    return _SRETUVAL(consumed);
> +}
> +
> +/* virtual */ SysStatus
> +FileInfoVirtFSDirVolatile::revalidate(char *name, uval namelen,  
> FileLinux::Stat *status)
> +{
> +    SysStatus rc;
> +
> +    /* This is somewhat odd, but we need to return ENOENT during  
> revalidation
> +     * if this directory is stale.  We *can not* return ESTALE.   
> This is so that we
> +     * can properly perform the purge operation during
> +     * DirLinuxFSVolatileDir::locked_purge since it will assert if  
> any error
> +     * code other than ENOENT is returned.
> +     */
> +    if (isStale()) {
> +	rc = _SERROR(2961, 0, ENOENT);
> +    } else {
> +	rc = FileInfoVirtFSDirStatic::revalidate(name, namelen, status);
> +	if (_FAILURE(rc)) {
> +	    rc = revalidateDynamic(name, namelen, status);
> +	}
> +    }
> +
> +    tassertMsg(_SUCCESS(rc) || _SGENCD(rc) == ENOENT,
> +	       "caller can only handle SUCCESS or ENOENT\n");
> +    return rc;
> +}
> diff -ru kitchsrc.orig/lib/libc/fslib/virtfs/FileInfoVirtFS.H  
> kitchsrc/lib/libc/fslib/virtfs/FileInfoVirtFS.H
> --- kitchsrc.orig/lib/libc/fslib/virtfs/FileInfoVirtFS.H	2006-09-14  
> 16:06:16.000000000 -0700
> +++ kitchsrc/lib/libc/fslib/virtfs/FileInfoVirtFS.H	2006-09-20  
> 14:34:19.000000000 -0700
> @@ -124,7 +124,6 @@
>  	return _SERROR(2580, 0, ENOTDIR);
>      }
>
> -
>  };
>
>  // Base class object that represents entries in a virtFS file system
> @@ -430,6 +429,19 @@
>  					    MultiLinkMgrLock* &lock,
>  					    FileLinux::Stat *status=NULL);
>      virtual SysStatus mountToNameSpace(const char *mpath);
> +
> +    /* isStale returns true if the directory itself is no longer  
> valid, e.g.
> +     * a pid directory in /proc when the process no longer exists.
> +     */
> +    virtual uval isStale()=0;
> +
> +    /* shouldRevalidate returns true if the directory contents are  
> potentially
> +     * invalid, e.g. entires in /proc/<pid>/fd when after have  
> been opened
> +     * or closed by process 'pid'.
> +     */
> +    virtual uval shouldRevalidate()=0;
> +
> +    static uval getRecLen(uval lengthString);
>  };
>
>  //Directory support for cases where directory contents are known at
> @@ -459,25 +471,82 @@
>      virtual SysStatus deleteFile();
>      virtual SysStatusUval getServerFileType();
>      virtual SysStatus createServerFileBlock(ServerFileRef &fref);
> +
> +    virtual uval isStale() {
> +	return 0;
> +    }
> +
> +    virtual uval shouldRevalidate() {
> +	return 0;
> +    }
>  };
>
> -#ifdef VOLATILEDIR
> -class FileInfoVirtFSDirVolatile : public FileInfoVirtFSDirBase {
> +/*
> + * FileInfoVirtFSDirVolatile is for directories that have volatile  
> directory
> + * listings (e.g. procfs) in addition to an optional set of static  
> entries.
> + *
> + * Derived classes should override the get*Dynamic calls to add the
> + * dynamic/volatile entries so that this class can merge the results
> + * with that of the static portion of the directory.
> + */
> +class FileInfoVirtFSDirVolatile : public FileInfoVirtFSDirStatic {
>  public:
> +    /*
> +     * The DYNAMIC_FLAG and DYNAMIC_MASK constants are used to  
> identify
> +     * if a getDents cookie is in the static or dynamic part of  
> the dir
> +     */
> +    static const uval DYNAMIC_FLAG = (0x1000000000000000UL);
> +    static const uval DYNAMIC_MASK = (0x0FFFFFFFFFFFFFFFUL);
> +
>      DEFINE_GLOBAL_NEW(FileInfoVirtFSDirVolatile);
> +    virtual ~FileInfoVirtFSDirVolatile() {};
> +
> +    /*
> +     * Override getStatus so that we can add the dynamic entries  
> to the
> +     * st_nlink count to the st_nlink returned by the virtfs base  
> classes.
> +     *
> +     * It is unclear if this should be done for locked_getStatus  
> as well.
> +     * The problem there is that we would want to keep track of  
> the number
> +     * of links returned by locked_getStatus and decrement  
> st_nlink by that
> +     * number when unlock_putStatus is called.  If this is needed,  
> we could
> +     * simply keep the count as part of this class, since it  
> wouldn't be
> +     * possible for locked_getStatus to be called twice (due to  
> the locking.)
> +     */
> +    virtual SysStatus getStatus(FileLinux::Stat *stat);
> +
> +    /*
> +     * We overlay on getFSFileOrServerFile rather than  
> locked_lookup because
> +     * locked_lookup requires jumping through some extra hoops to  
> format
> +     * up a DirEntry that just gets thrown away by the parent's  
> implementation
> +     * of getFSFileOrServerFile.
> +     */
> +    virtual SysStatus getFSFileOrServerFile(char *entryName, uval  
> entryLen,
> +					    FSFile **entryInfo,
> +					    ServerFileRef &ref,
> +					    MultiLinkMgrLock* &lock,
> +					    FileLinux::Stat *status=NULL);
>
> +    virtual SysStatusUval getDents(uval &cookie, struct direntk42  
> *buf,
> +				   uval len);
>
> -    virtual ~FileInfoVirtFSDirVolatile() {};
> +    virtual SysStatus revalidate(char *name, uval namelen,
> +				 FileLinux::Stat *status);
>
> -    virtual SysStatus locked_lookup(const char *name,
> -				    uval namelen, DirEntry &entry);
> +protected:
> +    virtual SysStatus getFSFileOrServerFileDynamic(char *entryName,
> +						   uval entryLen,
> +						   FSFile **entryInfo,
> +						   ServerFileRef &ref,
> +						   MultiLinkMgrLock* &lock,
> +						   FileLinux::Stat *status) = 0;
>
> -    virtual SysStatus add(const char *nm, uval len,  
> FileInfoVirtFS* finfo);
> +    virtual SysStatusUval getDentsDynamic(uval &cookie, struct  
> direntk42 *buf,
> +					  uval len, uval offset) = 0;
>
> -    virtual SysStatusUval getDents(uval &cookie, struct direntk42  
> *buf,
> -				   uval len);
> -};
> -#endif /* VOLATILEDIR */
> +    virtual SysStatus revalidateDynamic(char *name, uval namelen,
> +					FileLinux::Stat *status) = 0;
>
> +    virtual SysStatusUval getLinksDynamic() = 0;
> +};
>
>  #endif /* #ifndef __FILE_INFO_VIRT_FS_H_ */
> diff -ru kitchsrc.orig/lib/libc/fslib/virtfs/ServerFileDirVirtFS.H  
> kitchsrc/lib/libc/fslib/virtfs/ServerFileDirVirtFS.H
> --- kitchsrc.orig/lib/libc/fslib/virtfs/ServerFileDirVirtFS.H	 
> 2004-09-29 14:36:38.000000000 -0700
> +++ kitchsrc/lib/libc/fslib/virtfs/ServerFileDirVirtFS.H	2006-09-20  
> 17:04:46.000000000 -0700
> @@ -26,13 +26,27 @@
>  protected:
>      virtual SysStatus tryToDestroy();
>      uval invalidCache;
> -    FileInfoVirtFSDir* fivfDir;
>  public:
>      virtual SysStatus locked_revalidate() {
> +	SysStatus rc;
>  	if (!invalidCache) return 0;
> -	return locked_purge();
> +	rc = locked_purge();
> +	if (((FileInfoVirtFSDir *) fileInfo)->isStale()) {
> +	    rc = _SERROR(2962, 0, ESTALE);
> +	}
> +	return rc;
>      }
>      virtual uval shouldRevalidate() {
> +	/* Not all fs activity will result in markCacheInvalid() being  
> called
> +	 * before DirLinuxFSVolatile calls shouldRevaliate() on us.  So,  
> let's
> +	 * check with our fileinfo so that we can head off operations on  
> stale
> +	 * objects right away.
> +	 */
> +	tassertMsg(validFileInfo(), "invalid file info\n");
> +	if (((FileInfoVirtFSDir *) fileInfo)->isStale() ||
> +	    ((FileInfoVirtFSDir *) fileInfo)->shouldRevalidate()) {
> +	    markCacheInvalid();
> +	}
>  	return invalidCache;
>      }
>      virtual SysStatus markCacheInvalid() { invalidCache =1; return  
> 0; };
> _______________________________________________
> K42-discussion mailing list
> K42-discussion at ozlabs.org
> https://ozlabs.org/mailman/listinfo/k42-discussion




More information about the K42-discussion mailing list