os_atomic_t refcount;
os_blocker_id_t blocker;
os_completion_t completion;
+ os_completion_t notification;
char filename[OS_PATH_MAX];
} BlockInfo;
DblLnkLst_Init(&block->links);
os_atomic_set(&block->refcount, 1);
os_completion_init(&block->completion);
+ os_completion_init(&block->notification);
block->blocker = blocker;
return block;
}
os_completion_destroy(&block->completion);
+ os_completion_destroy(&block->notification);
os_kmem_cache_free(cache, block);
}
LOG(4, "Completing block on [%s] (%d waiters)\n",
block->filename, os_atomic_read(&block->refcount) - 1);
os_complete_all(&block->completion);
+ os_complete_all(&block->notification);
/* Now drop our reference */
BlockDropReference(block);
}
+/*
+ *----------------------------------------------------------------------------
+ *
+ * BlockWaitFileBlock --
+ *
+ * The caller will be blocked until any other thread accesses the file
+ * specified by the filename or the block on the file is removed.
+ *
+ * Results:
+ * Zero on success, error code on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+BlockWaitFileBlock(const char *filename, // IN: block to wait
+ const os_blocker_id_t blocker) // IN: blocker
+{
+ BlockInfo *block;
+ int retval = 0;
+
+ ASSERT(filename);
+
+ os_write_lock(&blockedFilesLock);
+ block = GetBlock(filename, blocker);
+ os_write_unlock(&blockedFilesLock);
+
+ if (!block) {
+ retval = OS_ENOENT;
+ return retval;
+ }
+
+ os_wait_for_completion(&block->notification);
+
+ return retval;
+}
+
+
/*
*----------------------------------------------------------------------------
*
block = cookie;
}
+ // Call the callback
+ os_complete_all(&block->notification);
+
LOG(4, "(%"OS_FMTTID") Waiting for completion on [%s]\n", os_threadid, filename);
error = os_wait_for_completion(&block->completion);
LOG(4, "(%"OS_FMTTID") Wokeup from block on [%s]\n", os_threadid, filename);
{ "/", S_IFDIR | 0555, 3, DIR_SIZE },
{ CONTROL_FILE, S_IFREG | 0600, 1, 0 },
{ REDIRECT_DIR, S_IFDIR | 0555, 3, DIR_SIZE },
+ { NOTIFY_DIR, S_IFDIR | 0555, 3, DIR_SIZE },
{ NULL, 0, 0, 0 }
};
static vmblockSpecialDirEntry symlinkDirEntry =
{ REDIRECT_DIR "/*", S_IFLNK | 0777, 1, -1 };
+static vmblockSpecialDirEntry notifyDirEntry =
+ { NOTIFY_DIR "/*", S_IFREG | 0444, 1, 0 };
/*
*-----------------------------------------------------------------------------
SetTimesToNow(statBuf);
return 0;
}
+ if (strncmp(path, NOTIFY_DIR, strlen(NOTIFY_DIR)) == 0) {
+ memset(statBuf, 0, sizeof *statBuf);
+ statBuf->st_mode = notifyDirEntry.mode;
+ statBuf->st_nlink = notifyDirEntry.nlink;
+ statBuf->st_size = notifyDirEntry.size;
+ SetTimesToNow(statBuf);
+ return 0;
+ }
return -ENOENT;
}
*/
int
-ExternalReadDir(const char *path, // IN: Full (real) path to
+ExternalReadDir(const char *blockPath, // IN:
+ const char *realPath, // IN: Full (real) path to
// directory to read.
void *buf, // OUT: Destination for
// directory listing.
struct stat statBuf;
DIR *dir = NULL;
- LOG(4, "%s: path: %s\n", __func__, path);
- dir = opendir(path);
+ LOG(4, "%s: blockPath: %s, realPath: %s\n", __func__, blockPath, realPath);
+ dir = opendir(realPath);
if (dir == NULL) {
return -errno;
}
*/
memset(&statBuf, 0, sizeof statBuf);
- statBuf.st_mode = S_IFLNK;
+ if (strncmp(blockPath, NOTIFY_DIR, strlen(NOTIFY_DIR)) == 0) {
+ statBuf.st_mode = S_IFREG;
+ } else {
+ statBuf.st_mode = S_IFLNK;
+ }
/* Clear errno because readdir won't change it if it succeeds. */
-
errno = 0;
+
while ((dentry = readdir(dir)) != NULL) {
status = filler(buf, dentry->d_name, &statBuf, 0);
if (status == 1) {
break;
}
}
+
if (errno != 0) {
return -errno;
}
(void)(filler(buf, ".", &dirStat, 0) ||
filler(buf, "..", &dirStat, 0) ||
filler(buf, VMBLOCK_DEVICE_NAME, &fileStat, 0) ||
- filler(buf, REDIRECT_DIR_NAME, &dirStat, 0));
+ filler(buf, REDIRECT_DIR_NAME, &dirStat, 0) ||
+ filler(buf, NOTIFY_DIR_NAME, &dirStat, 0));
return 0;
- } else if (strcmp(path, REDIRECT_DIR) == 0) {
- return ExternalReadDir(TARGET_DIR, buf, filler, offset, fileInfo);
+ } else if ( (strcmp(path, REDIRECT_DIR) == 0)
+ || (strcmp(path, NOTIFY_DIR) == 0)) {
+ return ExternalReadDir(path, TARGET_DIR, buf, filler, offset, fileInfo);
} else {
return -ENOENT;
}
char *uniqueValue = NULL;
- if (strcmp(path, CONTROL_FILE) != 0) {
+ if ( (strcmp(path, CONTROL_FILE) != 0)
+ && (strncmp(path, NOTIFY_DIR, strlen(NOTIFY_DIR)) != 0)) {
return -ENOENT;
}
off_t offset, // IN: Ignored.
struct fuse_file_info *fileInfo) // IN: Ignored.
{
+ char target[PATH_MAX+1];
+ char targetLink[PATH_MAX+1];
+ const char redirectPrefix[] = REDIRECT_DIR "/";
+ const char redirectPrefixLength = sizeof redirectPrefix - 1;
+ const char notifyPrefix[] = NOTIFY_DIR "/";
+ const char notifyPrefixLength = sizeof notifyPrefix - 1;
+ const char *relativePath = path + notifyPrefixLength;
+
LOG(4, "%s: path: %s, size: %"FMTSZ"u\n", __func__, path, size);
LOG(4, "%s: fileInfo->fh: %p\n", __func__,
FuseFileHandleToCharPointer(fileInfo->fh));
- ASSERT(strcmp(path, CONTROL_FILE) == 0);
- if (size < sizeof VMBLOCK_FUSE_READ_RESPONSE) {
- return -EINVAL;
+ if (strcmp(path, CONTROL_FILE) == 0) {
+ if (size < sizeof VMBLOCK_FUSE_READ_RESPONSE) {
+ return -EINVAL;
+ }
+ memcpy(buf, VMBLOCK_FUSE_READ_RESPONSE, sizeof VMBLOCK_FUSE_READ_RESPONSE);
+ return sizeof VMBLOCK_FUSE_READ_RESPONSE;
}
- memcpy(buf, VMBLOCK_FUSE_READ_RESPONSE, sizeof VMBLOCK_FUSE_READ_RESPONSE);
+ if (strncmp(path, NOTIFY_DIR, strlen(NOTIFY_DIR)) == 0) {
+ strlcpy(target, redirectPrefix, sizeof target);
+ strlcpy(target + redirectPrefixLength,
+ relativePath,
+ sizeof target - redirectPrefixLength);
+ if (RealReadLink(target, targetLink, sizeof targetLink) < 0) {
+ return -EINVAL;
+ }
+ return BlockWaitFileBlock(targetLink, OS_UNKNOWN_BLOCKER);
+ }
- return sizeof VMBLOCK_FUSE_READ_RESPONSE;
+ return -EINVAL;
}
/*
ASSERT(path);
ASSERT(fileInfo);
- ASSERT(strcmp(path, CONTROL_FILE) == 0);
- ASSERT(blockerId != NULL);
- BlockRemoveAllBlocks(blockerId);
+
+ if (strcmp(path, CONTROL_FILE) == 0) {
+ ASSERT(blockerId != NULL);
+ BlockRemoveAllBlocks(blockerId);
+ }
free(blockerId);
blockerId = NULL;
fileInfo->fh = CharPointerToFuseFileHandle(NULL);