[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