Browse Source

Reimplement directory caching (#78)

Replace the directory cache implementation.

* Fix unix domain socket lookup.

* Fix a bug in the getdents EINVAL case

* remove profiling code in dcache.c; cleaning up some style issues

* adding a note to the recursive path_lookupat() code

* remove a few compilation warnings

* Apply Chia-Che's suggested fixes; add more now-passing cases to LTP nice list.

* Ref counting bug for /proc/self/fd/.  Document and implement expected behavior in relevant helper function.
Don Porter 6 years ago
parent
commit
62f07c7181

+ 165 - 40
LibOS/shim/include/shim_fs.h

@@ -112,11 +112,22 @@ struct shim_fs_ops {
 #define DENTRY_ISLINK       0x0080  /* this dentry is a link */
 #define DENTRY_ISLINK       0x0080  /* this dentry is a link */
 #define DENTRY_ISDIRECTORY  0x0100  /* this dentry is a directory */
 #define DENTRY_ISDIRECTORY  0x0100  /* this dentry is a directory */
 #define DENTRY_LOCKED       0x0200  /* locked by mountpoints at children */
 #define DENTRY_LOCKED       0x0200  /* locked by mountpoints at children */
-#define DENTRY_REACHABLE    0x0400  /* permission checked to be reachable */
-#define DENTRY_UNREACHABLE  0x0800  /* permission checked to be unreachable */
+/* These flags are not used */
+//#define DENTRY_REACHABLE    0x0400  /* permission checked to be reachable */
+//#define DENTRY_UNREACHABLE  0x0800  /* permission checked to be unreachable */
 #define DENTRY_LISTED       0x1000  /* children in directory listed */
 #define DENTRY_LISTED       0x1000  /* children in directory listed */
 #define DENTRY_INO_UPDATED  0x2000  /* ino updated */
 #define DENTRY_INO_UPDATED  0x2000  /* ino updated */
-#define DENTRY_ANCESTER     0x4000
+#define DENTRY_ANCESTOR     0x4000 /* Auto-generated dentry to connect a mount
+                                    * point in the manifest to the root, when
+                                    * one or more intermediate directories do
+                                    * not exist on the underlying FS. The
+                                    * semantics of subsequent changes to such
+                                    * directories (or attempts to really
+                                    * create them) are not currently
+                                    * well-defined. */
+
+// Catch memory corruption issues by checking for invalid state values
+#define DENTRY_INVALID_FLAGS ~0x7FFF
 
 
 #define DCACHE_HASH_SIZE    1024
 #define DCACHE_HASH_SIZE    1024
 #define DCACHE_HASH(hash) ((hash) & (DCACHE_HASH_SIZE - 1))
 #define DCACHE_HASH(hash) ((hash) & (DCACHE_HASH_SIZE - 1))
@@ -132,6 +143,11 @@ struct shim_dentry {
     struct shim_qstr name;          /* caching the file's name. */
     struct shim_qstr name;          /* caching the file's name. */
 
 
 
 
+    /* DEP 6/16/17: For now, let's try not hashing; I suspect it is 
+     * overkill for most purposes.  I'll leave the field here for now,
+     * but propose we move to a per-directory table to accelerate lookups,
+     * rather than a global table, since this just supports one process.
+     */
     LIST_TYPE(shim_dentry) hlist;    /* to resolve collisions in
     LIST_TYPE(shim_dentry) hlist;    /* to resolve collisions in
                                        the hash table */
                                        the hash table */
     LIST_TYPE(shim_dentry) list;     /* put dentry to different list
     LIST_TYPE(shim_dentry) list;     /* put dentry to different list
@@ -159,8 +175,16 @@ struct shim_d_ops {
     int (*open) (struct shim_handle * hdl, struct shim_dentry * dent,
     int (*open) (struct shim_handle * hdl, struct shim_dentry * dent,
                  int flags);
                  int flags);
 
 
-    /* look up dentry and allocate internal data */
+    /* look up dentry and allocate internal data.
+     * 
+     * On a successful lookup  (non-error, can be negative),
+     * this function should call get_new_dentry(), populating additional fields,
+     * and storing the new dentry in dent.
+     * 
+     * Maybe drop force?
+     */
     int (*lookup) (struct shim_dentry * dent, bool force);
     int (*lookup) (struct shim_dentry * dent, bool force);
+    
     /* this is to check file type and access, returning the stat.st_mode */
     /* this is to check file type and access, returning the stat.st_mode */
     int (*mode) (struct shim_dentry * dent, mode_t * mode, bool force);
     int (*mode) (struct shim_dentry * dent, mode_t * mode, bool force);
 
 
@@ -231,9 +255,15 @@ extern struct shim_dentry * dentry_root;
 
 
 #define LOOKUP_FOLLOW            001
 #define LOOKUP_FOLLOW            001
 #define LOOKUP_DIRECTORY         002
 #define LOOKUP_DIRECTORY         002
-#define LOOKUP_CONTINUE          004
-#define LOOKUP_PARENT            010
-
+#define LOOKUP_CONTINUE          004 // No longer needed
+#define LOOKUP_PARENT            010 // Not sure we need this
+
+#define F_OK          0
+// XXX: Duplicate definition; should probably weed out includes of host system
+//include of unistd.h in future work
+//#define R_OK        001
+//#define W_OK        002
+//#define X_OK        004
 #define MAY_EXEC    001
 #define MAY_EXEC    001
 #define MAY_WRITE   002
 #define MAY_WRITE   002
 #define MAY_READ    004
 #define MAY_READ    004
@@ -246,9 +276,9 @@ extern struct shim_dentry * dentry_root;
 #define ACC_MODE(x) ((((x) == O_RDONLY || (x) == O_RDWR) ? MAY_READ : 0) | \
 #define ACC_MODE(x) ((((x) == O_RDONLY || (x) == O_RDWR) ? MAY_READ : 0) | \
                      (((x) == O_WRONLY || (x) == O_RDWR) ? MAY_WRITE : 0))
                      (((x) == O_WRONLY || (x) == O_RDWR) ? MAY_WRITE : 0))
 
 
-#define LOOKUP_OPEN             0100
-#define LOOKUP_CREATE           0200
-#define LOOKUP_ACCESS           0400
+#define LOOKUP_OPEN             0100 // Appears to be ignored
+#define LOOKUP_CREATE           0200 
+#define LOOKUP_ACCESS           0400 // Appears to be ignored
 #define LOOKUP_SYNC     (LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_ACCESS)
 #define LOOKUP_SYNC     (LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_ACCESS)
 
 
 enum lookup_type {
 enum lookup_type {
@@ -268,15 +298,9 @@ struct lookup {
     enum lookup_type last_type;
     enum lookup_type last_type;
 };
 };
 
 
-long get_dcache_stats (const char * name);
-
-void path_acquire (struct lookup * look);
-void path_release (struct lookup * look);
 
 
 /* initialization for fs and mounts */
 /* initialization for fs and mounts */
-int init_config (const char ** envp);
 int init_fs (void);
 int init_fs (void);
-int reinit_fs (void);
 int init_mount_root (void);
 int init_mount_root (void);
 int init_mount (void);
 int init_mount (void);
 
 
@@ -285,9 +309,9 @@ const char * get_file_name (const char * path, size_t len);
 
 
 /* file system operations */
 /* file system operations */
 int mount_fs (const char * mount_type, const char * mount_uri,
 int mount_fs (const char * mount_type, const char * mount_uri,
-              const char * mount_point);
+              const char * mount_point, struct shim_dentry *parent,
+              struct shim_dentry **dentp, int make_ancestor);
 int unmount_fs (const char * mount_point);
 int unmount_fs (const char * mount_point);
-int readdir_fs (HASHTYPE hash, struct shim_dirent ** dirent);
 int search_builtin_fs (const char * type, struct shim_mount ** fs);
 int search_builtin_fs (const char * type, struct shim_mount ** fs);
 
 
 void get_mount (struct shim_mount * mount);
 void get_mount (struct shim_mount * mount);
@@ -310,31 +334,108 @@ int walk_mounts (int (*walk) (struct shim_mount * mount, void * arg),
 
 
 /* functions for dcache supports */
 /* functions for dcache supports */
 int init_dcache (void);
 int init_dcache (void);
-int reinit_dcache (void);
 
 
 extern LOCKTYPE dcache_lock;
 extern LOCKTYPE dcache_lock;
 
 
+/* check permission (specified by mask) of a dentry. If force is not set,
+ * permission is considered granted on invalid dentries */
+/* Assume caller has acquired dcache_lock */
 int permission (struct shim_dentry * dent, int mask, bool force);
 int permission (struct shim_dentry * dent, int mask, bool force);
 
 
-int lookup_dentry (struct shim_dentry * base, const char * name, int namelen,
-                   bool force, struct shim_dentry ** new);
-
+/* This function looks up a single dentry based on its parent dentry pointer
+ * and the name.  Namelen is the length of char * name.
+ * The dentry is returned in pointer *new.
+ * 
+ * The force flag causes the libOS to query the underlying file system for the
+ * existence of the dentry, whereas without force, a negative dentry is
+ * treated as definitive.  In some cases, this can be elided as an
+ * optimization.
+ * 
+ * The caller should hold the dcache_lock.
+ */
+int lookup_dentry (struct shim_dentry * parent, const char * name, int namelen,
+                   bool force, struct shim_dentry ** new, struct shim_mount * fs);
+
+/* Looks up path under start dentry.  Saves in dent.
+ * 
+ * Assumes dcache_lock is held; main difference from path_lookupat is that
+ * dcache_lock is not released on return.
+ * 
+ * The refcount is dropped by one on the returned dentry.
+ * 
+ * The make_ancestor flag creates pseudo-dentries for any parent paths that
+ * are not in cache and do not exist on the underlying file system.  This is
+ * intended for use only in setting up the file system view specified in the manifest.
+ *
+ * If the file isnt' found, returns -ENOENT.
+ * 
+ * If the LOOKUP_DIRECTORY flag is set, and the found file isn't a directory, 
+ *  returns -ENOTDIR.
+ */
 int __path_lookupat (struct shim_dentry * start, const char * path, int flags,
 int __path_lookupat (struct shim_dentry * start, const char * path, int flags,
-                     struct shim_dentry ** dent);
+                     struct shim_dentry ** dent, int link_depth,
+                     struct shim_mount *fs, int make_ancestor);
+
+/* Just wraps __path_lookupat, but also acquires and releases the dcache_lock.
+ */
 int path_lookupat (struct shim_dentry * start, const char * name, int flags,
 int path_lookupat (struct shim_dentry * start, const char * name, int flags,
-                   struct shim_dentry ** dent);
+                   struct shim_dentry ** dent, struct shim_mount *fs);
+
+/* This function initializes dir to before a search, to either point
+ * to the current working directory (if dfd == AT_FDCWD), or to the handle pointed to by dfd,
+ * depending on the argument.  
+ * 
+ * Returns -EBADF if dfd is <0 or not a valid handle. 
+ * Returns -ENOTDIR if dfd is not a directory.
+ */
 int path_startat (int dfd, struct shim_dentry ** dir);
 int path_startat (int dfd, struct shim_dentry ** dir);
 
 
+/* Open path with given flags, in mode, similar to Unix open.
+ * 
+ * The start dentry specifies where to begin the search.
+ * hdl is an optional argument; if passed in, it is initialized to 
+ *   refer to the opened path.
+ * 
+ * The result is stored in dent.
+ */
+
 int open_namei (struct shim_handle * hdl, struct shim_dentry * start,
 int open_namei (struct shim_handle * hdl, struct shim_dentry * start,
                 const char * path, int flags, int mode,
                 const char * path, int flags, int mode,
                 struct shim_dentry ** dent);
                 struct shim_dentry ** dent);
 
 
+/* This function calls the low-level file system to do the work
+ * of opening file indicated by dent, and initializing it in hdl.
+ * Flags are standard open flags.
+ *
+ * If O_TRUNC is specified, this function is responsible for calling
+ * the underlying truncate function.
+ */
+
 int dentry_open (struct shim_handle * hdl, struct shim_dentry * dent,
 int dentry_open (struct shim_handle * hdl, struct shim_dentry * dent,
                  int flags);
                  int flags);
-int directory_open (struct shim_handle * hdl, struct shim_dentry * dent,
-                    int flags);
 
 
+/* This function enumerates a directory and caches the results in the dentry.
+ * 
+ * Input: A dentry for a directory in the DENTRY_ISDIRECTORY and not in the
+ * DENTRY_LISTED state.  The dentry DENTRY_LISTED flag is set upon success.
+ * 
+ * Return value: 0 on success, <0 on error
+ */
+int list_directory_dentry (struct shim_dentry *dir);
+
+/* This function caches the contents of a directory (dent), already
+ * in the listed state, in a buffer associated with a handle (hdl).
+ * 
+ * This function should only be called once on a handle.
+ * 
+ * Returns 0 on success, <0 on failure.
+ */
+int list_directory_handle (struct shim_dentry *dent, struct shim_handle *hdl );
+
+
+/* Increment the reference count on dent */
 void get_dentry (struct shim_dentry * dent);
 void get_dentry (struct shim_dentry * dent);
+/* Decrement the reference count on dent */
 void put_dentry (struct shim_dentry * dent);
 void put_dentry (struct shim_dentry * dent);
 
 
 static_inline
 static_inline
@@ -396,26 +497,50 @@ const char * dentry_get_name (struct shim_dentry * dent)
     return qstrgetstr(&dent->name);
     return qstrgetstr(&dent->name);
 }
 }
 
 
-struct shim_dentry * get_new_dentry (struct shim_dentry * parent,
-                                     const char * name, int namelen);
-
-void __set_parent_dentry (struct shim_dentry * child,
-                          struct shim_dentry * parent);
-void __unset_parent_dentry (struct shim_dentry * child,
-                            struct shim_dentry * parent);
-
-void __add_dcache (struct shim_dentry * dent, HASHTYPE * hashptr);
-void add_dcache (struct shim_dentry * dent, HASHTYPE * hashptr);
-
+/* Allocate and initialize a new dentry for path name, under
+ * parent.  Return the dentry.  
+ * 
+ * mount is the mountpoint the dentry is under; this is typically
+ * the parent->fs, but is passed explicitly for initializing 
+ * the dentry of a mountpoint.
+ * 
+ * If hashptr is passed (as an optimization), this is a hash
+ * of the name.
+ * 
+ * If parent is non-null, the ref count is 1; else it is zero.
+ * 
+ * This function also sets up both a name and a relative path
+ */
+struct shim_dentry * get_new_dentry (struct shim_mount *mount,
+                                     struct shim_dentry * parent,
+                                     const char * name, int namelen,
+                                     HASHTYPE * hashptr);
+
+/* This function searches for name/namelen (as the relative path; 
+ * path/pathlen is the fully-qualified path), 
+ * under parent dentry (start).
+ * 
+ * If requested, the expected hash of the dentry is returned in hashptr,
+ * primarily so that the hashing can be reused to add the dentry later.
+ * 
+ * The reference count on the found dentry is incremented by one.
+ *
+ * Used only by shim_namei.c 
+ */
 struct shim_dentry *
 struct shim_dentry *
 __lookup_dcache (struct shim_dentry * start, const char * name, int namelen,
 __lookup_dcache (struct shim_dentry * start, const char * name, int namelen,
                  const char * path, int pathlen, HASHTYPE * hashptr);
                  const char * path, int pathlen, HASHTYPE * hashptr);
-struct shim_dentry *
-lookup_dcache (struct shim_dentry * start, const char * name, int namelen,
-               const char * path, int pathlen, HASHTYPE * hashptr);
 
 
+/* This function recursively deletes and frees all dentries under root 
+ * 
+ * XXX: Current code doesn't do a free..
+ */
 int __del_dentry_tree(struct shim_dentry * root);
 int __del_dentry_tree(struct shim_dentry * root);
 
 
+/* XXX: Future work: current dcache never shrinks.  Would be nice 
+ * to be able to do something like LRU under space pressure, although
+ * for a single app, this may be over-kill. */
+
 /* hashing utilities */
 /* hashing utilities */
 #define MOUNT_HASH_BYTE     1
 #define MOUNT_HASH_BYTE     1
 #define MOUNT_HASH_WIDTH    8
 #define MOUNT_HASH_WIDTH    8

+ 14 - 7
LibOS/shim/src/bookkeep/shim_handle.c

@@ -53,8 +53,13 @@ static inline int init_tty_handle (struct shim_handle * hdl, bool write)
 {
 {
     struct shim_dentry * dent = NULL;
     struct shim_dentry * dent = NULL;
     int ret;
     int ret;
-
-    if ((ret = path_lookupat(NULL, "/dev/tty", LOOKUP_OPEN, &dent)) < 0)
+    struct shim_thread * cur_thread = get_cur_thread();
+    
+    /* XXX: Try getting the root FS from current thread? */
+    assert(cur_thread);
+    assert(cur_thread->root);
+    if ((ret = path_lookupat(cur_thread->root, "/dev/tty", LOOKUP_OPEN, &dent,
+                             cur_thread->root->fs)) < 0)
         return ret;
         return ret;
 
 
     int flags = (write ? O_WRONLY : O_RDONLY)|O_APPEND;
     int flags = (write ? O_WRONLY : O_RDONLY)|O_APPEND;
@@ -94,7 +99,7 @@ static inline int init_exec_handle (struct shim_thread * thread)
     struct shim_mount * fs = find_mount_from_uri(PAL_CB(executable));
     struct shim_mount * fs = find_mount_from_uri(PAL_CB(executable));
     if (fs) {
     if (fs) {
         path_lookupat(fs->root, PAL_CB(executable) + fs->uri.len, 0,
         path_lookupat(fs->root, PAL_CB(executable) + fs->uri.len, 0,
-                      &exec->dentry);
+                      &exec->dentry, fs);
         set_handle_fs(exec, fs);
         set_handle_fs(exec, fs);
         if (exec->dentry) {
         if (exec->dentry) {
             int len;
             int len;
@@ -480,10 +485,12 @@ void close_handle (struct shim_handle * hdl)
                 dir->dotdot = NULL;
                 dir->dotdot = NULL;
             }
             }
 
 
-            while (dir->ptr && *dir->ptr) {
-                struct shim_dentry * dent = *dir->ptr;
-                put_dentry(dent);
-                *(dir->ptr++) = NULL;
+            if (dir->ptr != (void *) -1) {
+                while (dir->ptr && *dir->ptr) {
+                    struct shim_dentry * dent = *dir->ptr;
+                    put_dentry(dent);
+                    *(dir->ptr++) = NULL;
+                }
             }
             }
         } else {
         } else {
             if (hdl->fs && hdl->fs->fs_ops &&
             if (hdl->fs && hdl->fs->fs_ops &&

+ 4 - 2
LibOS/shim/src/bookkeep/shim_thread.c

@@ -220,11 +220,13 @@ struct shim_thread * get_new_thread (IDTYPE new_tid)
     } else {
     } else {
         /* default pid and pgid equals to tid */
         /* default pid and pgid equals to tid */
         thread->ppid = thread->pgid = thread->tgid = new_tid;
         thread->ppid = thread->pgid = thread->tgid = new_tid;
-        path_lookupat(NULL, "/", 0, &thread->root);
+        /* This case should fall back to the global root of the file system.
+         */
+        path_lookupat(NULL, "/", 0, &thread->root, NULL);
         char dir_cfg[CONFIG_MAX];
         char dir_cfg[CONFIG_MAX];
         if (root_config &&
         if (root_config &&
             get_config(root_config, "fs.start_dir", dir_cfg, CONFIG_MAX) > 0) {
             get_config(root_config, "fs.start_dir", dir_cfg, CONFIG_MAX) > 0) {
-            path_lookupat(NULL, dir_cfg, 0, &thread->cwd);
+            path_lookupat(NULL, dir_cfg, 0, &thread->cwd, NULL);
         } else if (thread->root) {
         } else if (thread->root) {
             get_dentry(thread->root);
             get_dentry(thread->root);
             thread->cwd = thread->root;
             thread->cwd = thread->root;

+ 0 - 1
LibOS/shim/src/bookkeep/shim_vma.c

@@ -893,7 +893,6 @@ static struct shim_vma * __lookup_supervma (const void * addr, uint64_t length,
     struct shim_vma * tmp, * prev = NULL;
     struct shim_vma * tmp, * prev = NULL;
     
     
     listp_for_each_entry(tmp, &vma_list, list) {
     listp_for_each_entry(tmp, &vma_list, list) {
-
         if (test_vma_contain(tmp, addr, length)) {
         if (test_vma_contain(tmp, addr, length)) {
             if (pprev)
             if (pprev)
                 *pprev = prev;
                 *pprev = prev;

+ 1 - 1
LibOS/shim/src/elf/shim_rtld.c

@@ -1400,7 +1400,7 @@ static int __load_interp_object (struct link_map * exec_map)
         struct shim_dentry * dent = NULL;
         struct shim_dentry * dent = NULL;
         int ret = 0;
         int ret = 0;
 
 
-        if ((ret = path_lookupat(NULL, interp_path, LOOKUP_OPEN, &dent)) < 0 ||
+        if ((ret = path_lookupat(NULL, interp_path, LOOKUP_OPEN, &dent, NULL)) < 0 ||
             dent->state & DENTRY_NEGATIVE)
             dent->state & DENTRY_NEGATIVE)
             continue;
             continue;
 
 

+ 0 - 2
LibOS/shim/src/fs/chroot/fs.c

@@ -387,8 +387,6 @@ static int chroot_stat (struct shim_dentry * dent, struct stat * statbuf)
 
 
 static int chroot_lookup (struct shim_dentry * dent, bool force)
 static int chroot_lookup (struct shim_dentry * dent, bool force)
 {
 {
-    if (!force)
-        return -ESKIPPED;
 
 
     return query_dentry(dent, NULL, NULL, NULL);
     return query_dentry(dent, NULL, NULL, NULL);
 }
 }

+ 1 - 0
LibOS/shim/src/fs/dev/fs.c

@@ -240,6 +240,7 @@ static int dev_open (struct shim_handle * hdl, struct shim_dentry * dent,
 static int dev_lookup (struct shim_dentry * dent, bool force)
 static int dev_lookup (struct shim_dentry * dent, bool force)
 {
 {
     if (qstrempty(&dent->rel_path)) {
     if (qstrempty(&dent->rel_path)) {
+        dent->state |= DENTRY_ISDIRECTORY;
         dent->ino = DEV_INO_BASE;
         dent->ino = DEV_INO_BASE;
         return 0;
         return 0;
     }
     }

+ 2 - 2
LibOS/shim/src/fs/proc/fs.c

@@ -177,13 +177,13 @@ static int proc_lookup (struct shim_dentry * dent, bool force)
     }
     }
 
 
     /* don't care about forced or not */
     /* don't care about forced or not */
-    const struct proc_ent * ent;
+    const struct proc_ent * ent = NULL;
     int ret = proc_match_name(qstrgetstr(&dent->rel_path), &ent);
     int ret = proc_match_name(qstrgetstr(&dent->rel_path), &ent);
 
 
     if (!ret && ent->dir)
     if (!ret && ent->dir)
         dent->state |= DENTRY_ISDIRECTORY;
         dent->state |= DENTRY_ISDIRECTORY;
 
 
-    if (ent->fs_ops && ent->fs_ops->follow_link)
+    if (ent && ent->fs_ops && ent->fs_ops->follow_link)
         dent->state |= DENTRY_ISLINK;
         dent->state |= DENTRY_ISLINK;
 
 
      return ret;
      return ret;

+ 3 - 1
LibOS/shim/src/fs/proc/ipc-thread.c

@@ -101,7 +101,9 @@ do_ipc:
         qstrsetstr(link, (char *) ipc_data, strlen((char *) ipc_data));
         qstrsetstr(link, (char *) ipc_data, strlen((char *) ipc_data));
 
 
     if (dentptr) {
     if (dentptr) {
-        ret = path_lookupat(NULL, (char *) ipc_data, 0, &dent);
+        /* XXX: Not sure how to handle this case yet */
+        assert (0);
+        ret = path_lookupat(NULL, (char *) ipc_data, 0, &dent, NULL);
         if (ret < 0)
         if (ret < 0)
             goto out;
             goto out;
 
 

+ 6 - 3
LibOS/shim/src/fs/proc/thread.c

@@ -117,7 +117,7 @@ static int find_thread_link (const char * name, struct shim_qstr * link,
     if (nextnext) {
     if (nextnext) {
         struct shim_dentry * next_dent = NULL;
         struct shim_dentry * next_dent = NULL;
 
 
-        ret = path_lookupat(dent, nextnext, 0, &next_dent);
+        ret = path_lookupat(dent, nextnext, 0, &next_dent, dent->fs);
         if (ret < 0)
         if (ret < 0)
             goto out;
             goto out;
 
 
@@ -221,6 +221,7 @@ static const struct proc_fs_ops fs_thread_link = {
             .follow_link    = &proc_thread_link_follow_link,
             .follow_link    = &proc_thread_link_follow_link,
         };
         };
 
 
+/* If *phdl is returned on success, the ref count is incremented */
 static int parse_thread_fd (const char * name, const char ** rest,
 static int parse_thread_fd (const char * name, const char ** rest,
                             struct shim_handle ** phdl)
                             struct shim_handle ** phdl)
 {
 {
@@ -262,8 +263,10 @@ static int parse_thread_fd (const char * name, const char ** rest,
         return -ENOENT;
         return -ENOENT;
     }
     }
 
 
-    if (phdl)
+    if (phdl) {
         *phdl = handle_map->map[fd]->handle;
         *phdl = handle_map->map[fd]->handle;
+        get_handle(*phdl);
+    }
 
 
     unlock(handle_map->lock);
     unlock(handle_map->lock);
 
 
@@ -368,7 +371,7 @@ static int find_thread_each_fd (const char * name, struct shim_qstr * link,
     if (rest) {
     if (rest) {
         struct shim_dentry * next_dent = NULL;
         struct shim_dentry * next_dent = NULL;
 
 
-        ret = path_lookupat(dent, rest, 0, &next_dent);
+        ret = path_lookupat(dent, rest, 0, &next_dent, dent->fs);
         if (ret < 0)
         if (ret < 0)
             goto out;
             goto out;
 
 

+ 196 - 332
LibOS/shim/src/fs/shim_dcache.c

@@ -1,7 +1,8 @@
 /* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */
 /* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */
 /* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */
 /* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */
 
 
-/* Copyright (C) 2014 OSCAR lab, Stony Brook University
+/* Copyright (C) 2014 Stony Brook University, 
+   2017 University of North Carolina at Chapel Hill and Fortanix, Inc.
    This file is part of Graphene Library OS.
    This file is part of Graphene Library OS.
 
 
    Graphene Library OS is free software: you can redistribute it and/or
    Graphene Library OS is free software: you can redistribute it and/or
@@ -21,8 +22,6 @@
  * shim_dcache.c
  * shim_dcache.c
  *
  *
  * This file contains codes for maintaining directory cache in library OS.
  * This file contains codes for maintaining directory cache in library OS.
- * The source codes are imported from Linux kernel, but simplified according
- * to the characteristic of library OS.
  */
  */
 
 
 #include <shim_types.h>
 #include <shim_types.h>
@@ -33,34 +32,8 @@
 
 
 #include <list.h>
 #include <list.h>
 
 
-/* As best I can tell, dentries are added to this list and then never touched
- * again */
-/* Links to shim_dentry->list */
-static LISTP_TYPE(shim_dentry) dentry_list = LISTP_INIT;
-
-/* Attaches to shim_dentry->hlist */
-static LISTP_TYPE(shim_dentry) dcache_htable[DCACHE_HASH_SIZE] = { LISTP_INIT };
-
 LOCKTYPE dcache_lock;
 LOCKTYPE dcache_lock;
 
 
-struct shim_dcache_stats {
-    long memsize;
-    long nentries;
-};
-
-static struct shim_dcache_stats dcache_stats;
-
-long get_dcache_stats (const char * name)
-{
-    if (strcmp_static(name, "memsize"))
-        return dcache_stats.memsize;
-
-    if (strcmp_static(name, "nentries"))
-        return dcache_stats.nentries;
-
-    return 0;
-}
-
 #define DCACHE_MGR_ALLOC    64
 #define DCACHE_MGR_ALLOC    64
 #define PAGE_SIZE           allocsize
 #define PAGE_SIZE           allocsize
 
 
@@ -71,8 +44,12 @@ static MEM_MGR dentry_mgr = NULL;
 
 
 struct shim_dentry * dentry_root = NULL;
 struct shim_dentry * dentry_root = NULL;
 
 
-//#define DEBUG_DCACHE
-//#define DEBUG_REF
+static inline
+HASHTYPE hash_dentry (struct shim_dentry * start, const char * path, int len)
+{
+    return rehash_path(start ? start->rel_path.hash : 0,
+                       path, len, NULL);
+}
 
 
 static struct shim_dentry * alloc_dentry (void)
 static struct shim_dentry * alloc_dentry (void)
 {
 {
@@ -82,9 +59,6 @@ static struct shim_dentry * alloc_dentry (void)
     if (!dent)
     if (!dent)
         return NULL;
         return NULL;
 
 
-    dcache_stats.memsize += sizeof(struct shim_dentry);
-    dcache_stats.nentries++;
-
     memset(dent, 0, sizeof(struct shim_dentry));
     memset(dent, 0, sizeof(struct shim_dentry));
 
 
     dent->mode = NO_MODE;
     dent->mode = NO_MODE;
@@ -94,139 +68,37 @@ static struct shim_dentry * alloc_dentry (void)
     INIT_LISTP(&dent->children);
     INIT_LISTP(&dent->children);
     INIT_LIST_HEAD(dent, siblings);
     INIT_LIST_HEAD(dent, siblings);
 
 
-    if (locked(dcache_lock)) {
-        listp_add(dent, &dentry_list, list);
-    } else {
-        lock(dcache_lock);
-        listp_add(dent, &dentry_list, list);
-        unlock(dcache_lock);
-    }
-
     return dent;
     return dent;
 }
 }
 
 
-DEFINE_PROFILE_CATAGORY(dcache, );
-DEFINE_PROFILE_INTERVAL(total_init_dcache, dcache);
-DEFINE_PROFILE_CATAGORY(within_init_dcache, dcache);
-DEFINE_PROFILE_INTERVAL(dcache_init_memory, within_init_dcache);
-DEFINE_PROFILE_INTERVAL(dcache_init_lock, within_init_dcache);
-DEFINE_PROFILE_INTERVAL(dcache_init_root_entry, within_init_dcache);
 
 
 int init_dcache (void)
 int init_dcache (void)
 {
 {
-#ifdef PROFILE
-    unsigned long begin_time = GET_PROFILE_INTERVAL();
-    BEGIN_PROFILE_INTERVAL_SET(begin_time);
-#endif
-
     dentry_mgr = create_mem_mgr(init_align_up(DCACHE_MGR_ALLOC));
     dentry_mgr = create_mem_mgr(init_align_up(DCACHE_MGR_ALLOC));
-    SAVE_PROFILE_INTERVAL(dcache_init_memory);
 
 
     create_lock(dcache_lock);
     create_lock(dcache_lock);
-    SAVE_PROFILE_INTERVAL(dcache_init_lock);
 
 
     dentry_root = alloc_dentry();
     dentry_root = alloc_dentry();
 
 
-    qstrsetstr(&dentry_root->rel_path, "", 0);
-    qstrsetstr(&dentry_root->name,     "", 0);
-
+    /* The root is special; we assume it won't change or be freed, and 
+     * set its refcount to 1. */
     get_dentry(dentry_root);
     get_dentry(dentry_root);
-    SAVE_PROFILE_INTERVAL(dcache_init_root_entry);
 
 
-    SAVE_PROFILE_INTERVAL_SINCE(total_init_dcache, begin_time);
-    return 0;
-}
-
-int reinit_dcache (void)
-{
-    create_lock(dcache_lock);
+    /* Initialize the root to a valid state, as a low-level lookup
+     *  will fail. */
+    dentry_root->state |= DENTRY_VALID;
 
 
-    return 0;
-}
+    /* The root should be a directory too*/
+    dentry_root->state |= DENTRY_ISDIRECTORY;
 
 
-/* remove from the hash table, so that a lookup will fail. */
-static void __del_dcache (struct shim_dentry * dent)
-{
-    if (!(dent->state & DENTRY_HASHED))
-        return;
-
-    /* DEP 5/15/17: I believe that, if a dentry is in the DENTRY_HASHED state,
-     * that the hash field is always valid. */
-    LISTP_TYPE(shim_dentry) * head = &dcache_htable[DCACHE_HASH(dent->rel_path.hash)];
-    dent->state &= ~DENTRY_HASHED;
-    listp_del_init(dent, head, hlist);
-
-#ifdef DEBUG_DCACHE
-    debug("del dcache %p(%s/%s) (mount = %p)\n",
-          dent, dent->fs ? qstrgetstr(&dent->fs->path) : "",
-          qstrgetstr(&dent->rel_path), dent->fs);
-#endif
-}
-
-static int __internal_put_dentry (struct shim_dentry * dent);
-
-/* Release a dentry whose ref count has gone to zero. */
-static inline void __dput_dentry (struct shim_dentry * dent)
-{
-    while (1) {
-        /* if the dentry is never in the hash table, we are happy to
-           drop it */
-        if (!(dent->state & DENTRY_HASHED))
-            goto kill;
-
-        /* move the node to unused list unless it is persistent */
-        if (!(dent->state & DENTRY_PERSIST)) {
-            dent->state |= DENTRY_RECENTLY;
-            /* DEP: The only reference I see to this field is being placed on 
-             * the unused list. It seems that sometimes the dent is not
-             * on a list; just hack this for now; this code will be reworked
-             * soon anyway.
-             */
-            /* Chia-Che 10/17/17: Originally we place all the freed
-             * dentries on an unused list, now we just maintain a long list
-             * of all dentries. */
-        }
-
-        /* we don't delete the dentry from dcache because it might
-           be acquired and used again, unless it gets recycled due
-           to memory pressure */
-        break;
-
-kill:   {
-            if (dent->fs && dent->fs->d_ops && dent->fs->d_ops->dput)
-                dent->fs->d_ops->dput(dent);
-
-            struct shim_dentry * parent = dent->parent;
-
-            if (!parent)
-                break;
-
-            listp_del(dent, &parent->children, siblings); /* remove from parent's list of children */
-            listp_del(dent, &dentry_list, list);
-            /* we can free this dentry */
-            free_mem_obj_to_mgr(dentry_mgr, dent);
-            dent = parent;
-
-            if (__internal_put_dentry(dent))
-                break;
-        }
-    }
-}
-
-static int __internal_put_dentry (struct shim_dentry * dent)
-{
-    int count = REF_DEC(dent->ref_count);
-
-#ifdef DEBUG_REF
-    debug("put dentry %p(%s/%s) (ref_count = %d)\n", dent,
-          dent->fs ?
-          qstrgetstr(&dent->fs->path) : "",
-          qstrgetstr(&dent->rel_path), count);
-#endif
+    qstrsetstr(&dentry_root->name,     "", 0);
+    qstrsetstr(&dentry_root->rel_path, "", 0);
 
 
-    return count;
+    get_dentry(dentry_root);
+    return 0;
 }
 }
 
 
+/* Increment the reference count for a dentry */
 void get_dentry (struct shim_dentry * dent)
 void get_dentry (struct shim_dentry * dent)
 {
 {
 #ifdef DEBUG_REF
 #ifdef DEBUG_REF
@@ -241,219 +113,208 @@ void get_dentry (struct shim_dentry * dent)
 #endif
 #endif
 }
 }
 
 
-void put_dentry (struct shim_dentry * dent)
-{
-    if (__internal_put_dentry(dent))
-        return;
+static void free_dentry (struct shim_dentry *dent) {
+    free_mem_obj_to_mgr(dentry_mgr, dent);
+}
 
 
-    if (locked(dcache_lock)) {
-        __dput_dentry(dent);
-    } else {
-        lock(dcache_lock);
-        __dput_dentry(dent);
-        unlock(dcache_lock);
+/* Decrement the reference count on dent.
+ * 
+ * For now, we don't have an eviction policy, so just
+ * keep everything.  
+ * 
+ * If a dentry is on the children list of a parent, it has 
+ * a refcount of at least 1.  
+ * 
+ * If the ref count ever hits zero, we free the dentry.
+ *
+ */
+void put_dentry (struct shim_dentry * dent) {
+    int count = REF_DEC(dent->ref_count);
+    assert (count >= 0);
+    // We don't expect this to commonly free a dentry, and may represent a
+    // reference counting bug.
+    if (count == 0) {
+        debug("XXX Churn Warning: Freeing dentry %p; may not be expected\n", dent);
+        // Add some assertions that the dentry is properly cleaned up, like it
+        // isn't on a parent's children list 
+        assert(list_empty(dent, siblings));
+        free_dentry(dent);
     }
     }
+
+    return;
 }
 }
 
 
-struct shim_dentry * get_new_dentry (struct shim_dentry * parent,
-                                     const char * name, int namelen)
+/* Allocate and initialize a new dentry for path name, under
+ * parent.  Return the dentry.  
+ * 
+ * mount is the mountpoint the dentry is under; this is typically
+ * the parent->fs, but is passed explicitly for initializing 
+ * the dentry of a mountpoint.
+ * 
+ * If hashptr is passed (as an optimization), this is a hash
+ * of the name.
+ * 
+ * If parent is non-null, the ref count is 1; else it is zero.
+ * 
+ * This function also sets up both a name and a relative path
+ */
+struct shim_dentry * get_new_dentry (struct shim_mount *mount,
+                                     struct shim_dentry * parent,
+                                     const char * name, int namelen,
+                                     HASHTYPE * hashptr)
 {
 {
     struct shim_dentry * dent = alloc_dentry();
     struct shim_dentry * dent = alloc_dentry();
-
+    HASHTYPE hash;
+    
     if (!dent)
     if (!dent)
         return NULL;
         return NULL;
 
 
-    REF_SET(dent->ref_count, 0);
+    if (hashptr) {
+#ifdef DEBUG
+        // For debug builds, assert that the hash passed in is correct.
+        assert(*hashptr == hash_dentry(parent, name, namelen));
+#endif
+        hash = *hashptr;
+    } else
+        hash = hash_dentry(parent, name, namelen);
+    
     qstrsetstr(&dent->name, name, namelen);
     qstrsetstr(&dent->name, name, namelen);
+    dent->rel_path.hash = hash;
+    /* DEP 6/16/17: Not sure this flag is strictly necessary. 
+     * But keeping it for now.
+     */
+    dent->state |= DENTRY_HASHED;
 
 
-    if (!parent) {
-        qstrsetstr(&dent->rel_path, name, namelen);
-        return dent;
+    if (mount) {
+        get_mount(mount);
+        dent->fs = mount;
     }
     }
-
-    if (!qstrempty(&parent->rel_path)) {
-        const char * strs[] = { qstrgetstr(&parent->rel_path), "/", name };
-        size_t lens[] = { parent->rel_path.len, 1, namelen };
-        qstrsetstrs(&dent->rel_path, 3, strs, lens);
-    } else
+    
+    if (parent) {
+        // Increment both dentries' ref counts once they are linked
+        get_dentry(parent);
+        get_dentry(dent);
+        listp_add_tail(dent, &parent->children, siblings);
+        dent->parent = parent;
+        parent->nchildren++;
+
+        if (!qstrempty(&parent->rel_path)) {
+            const char * strs[] = { qstrgetstr(&parent->rel_path), "/", name };
+            size_t lens[] = { parent->rel_path.len, 1, namelen };
+            qstrsetstrs(&dent->rel_path, 3, strs, lens);
+        } else
+            qstrsetstr(&dent->rel_path, name, namelen);
+    } else {
         qstrsetstr(&dent->rel_path, name, namelen);
         qstrsetstr(&dent->rel_path, name, namelen);
-
-    return dent;
-}
-
-void __set_parent_dentry (struct shim_dentry * child,
-                          struct shim_dentry * parent)
-{
-    if (child->parent == parent)
-        return;
-
-    assert(!child->parent);
-    get_dentry(parent);
-    listp_add_tail(child, &parent->children, siblings);
-    child->parent = parent;
-    parent->nchildren++;
-}
-
-void __unset_parent_dentry (struct shim_dentry * child,
-                            struct shim_dentry * parent)
-{
-    if (child->parent != parent)
-        return;
-
-    assert(child->parent);
-    listp_del_init(child, &parent->children, siblings);
-    child->parent = NULL;
-
-    parent->nchildren--;
-    put_dentry(parent);
-}
-
-static inline
-HASHTYPE hash_dentry (struct shim_dentry * start, const char * path, int len)
-{
-    return rehash_path(start ? start->rel_path.hash : 0,
-                       path, len, NULL);
-}
-
-void __add_dcache (struct shim_dentry * dent, HASHTYPE * hashptr)
-{
-    LISTP_TYPE(shim_dentry) * head;
-
-    if (hashptr) {
-        dent->rel_path.hash = *hashptr;
-        goto add_hash;
-    }
-
-    if (!dent->parent) {
-        dent->rel_path.hash = dent->fs ? dent->fs->path.hash : 0;
-        goto add_hash;
     }
     }
 
 
-    dent->rel_path.hash = hash_dentry(dent->parent, dentry_get_name(dent),
-                                      dent->name.len);
-
-add_hash:
-    head = &dcache_htable[DCACHE_HASH(dent->rel_path.hash)];
-    listp_add(dent, head, hlist);
-    dent->state |= DENTRY_HASHED;
-
-#ifdef DEBUG_DCACHE
-    debug("add dcache %p(%s/%s) (mount = %p)\n",
-          dent, dent->fs ? qstrgetstr(&dent->fs->path) : "",
-          qstrgetstr(&dent->rel_path), dent->fs);
-#endif
-}
-
-void add_dcache (struct shim_dentry * dent, HASHTYPE * hashptr)
-{
-    lock(dcache_lock);
-    __add_dcache(dent, hashptr);
-    unlock(dcache_lock);
+    return dent;
 }
 }
 
 
+/* This function searches for name/namelen (as the relative path) under 
+ * the parent directory (start).
+ * 
+ * path/pathlen is the fully-qualified path, and an optional (unused)
+ * argument.  XXX: I am not sure what the case is where the full path
+ * would resolve but the relative path would not; consider dropping
+ * this argument, or documenting the reason (after testing).
+ * 
+ * If requested, the expected hash of the dentry is returned in hashptr,
+ * primarily so that the hashing can be reused to add the dentry later.
+ * 
+ * The reference count on the found dentry is incremented by one.
+ * 
+ * Used only by shim_namei.c 
+ */
 struct shim_dentry *
 struct shim_dentry *
 __lookup_dcache (struct shim_dentry * start, const char * name, int namelen,
 __lookup_dcache (struct shim_dentry * start, const char * name, int namelen,
-                 const char * path, int pathlen, HASHTYPE * hashptr)
-{
+                 const char * path, int pathlen, HASHTYPE * hashptr) {
+
+    /* In this implementation, we just look at the children 
+     * under the parent and see if there are matches.  It so,
+     * return it; if not, don't.  
+     * 
+     * To minimize disruption (and possibly for future optimization)
+     * we are keeping hashes, so let's start with that for a marginally
+     * faster comparison 
+     */
     HASHTYPE hash = hash_dentry(start, name, namelen);
     HASHTYPE hash = hash_dentry(start, name, namelen);
-    struct shim_dentry * dent, * found = NULL;
-    LISTP_TYPE(shim_dentry) * head = &dcache_htable[DCACHE_HASH(hash)];
-
-    /* walk through all the nodes in the hash bucket, find the droids we're
-       looking for */
-    listp_for_each_entry(dent, head, hlist) {
-        if ((dent->state & DENTRY_MOUNTPOINT) ||
-            dent->rel_path.hash != hash)
+    struct shim_dentry *dent, *found = NULL;
+
+    /* If start is NULL, there will be no hit in the cache.
+     * This mainly happens when boostrapping; in general, we assume the 
+     * caller will use the current root or cwd.
+     */
+    if (!start) return NULL;
+
+    /* If we are looking up an empty string, return start */
+    if (namelen == 0) {
+        found = start;
+        goto out;
+    }
+    
+    listp_for_each_entry(dent, &start->children, siblings) {
+        /* DEP 6/20/XX: The old code skipped mountpoints; I don't see any good
+         * reason for mount point lookup to fail, at least in this code.
+         * Keeping a note just in case.  That is why you always leave a note.
+         */
+        //if (dent->state & DENTRY_MOUNTPOINT)
+        //continue;
+
+        // Check for memory corruption
+        assert(0 == (dent->state & DENTRY_INVALID_FLAGS));
+        
+        /* Compare the hash first */
+        if (dent->rel_path.hash != hash)
             continue;
             continue;
 
 
-        /* first we compare the filename */
+        /* I think comparing the relative path is adequate; with a global 
+         * hash table, a full path comparison may be needed, but I think 
+         * we can assume a parent has children with unique names */
         const char * filename = get_file_name(name, namelen);
         const char * filename = get_file_name(name, namelen);
-        if (memcmp(dentry_get_name(dent), filename, name + namelen - filename))
+        const char * dname = dentry_get_name(dent);
+        int dname_len = strlen(dname);
+        int fname_len = name + namelen - filename;
+        if (dname_len != fname_len || memcmp(dname, filename, fname_len))
             continue;
             continue;
 
 
-        if (filename == name) {
-            struct shim_dentry * d = dent;
-            while (d && !d->parent && d->fs)
-                d = d->fs->mount_point;
-            if (d && d->parent && d->parent != start)
-                continue;
-        }
-
-        if (path && pathlen && filename != path) {
-            const char * fullpath;
-            int fullpathlen;
-            fullpath = dentry_get_path(dent, true, &fullpathlen);
-            if (pathlen > fullpathlen)
-                continue;
-            fullpath += fullpathlen - pathlen;
-            if (fullpath[-1] != '/')
-                continue;
-            if (memcmp(fullpath, path, pathlen))
-                continue;
-        }
-
+        /* If we get this far, we have a match */
         get_dentry(dent);
         get_dentry(dent);
         found = dent;
         found = dent;
         break;
         break;
     }
     }
 
 
+out:
     if (hashptr)
     if (hashptr)
         *hashptr = hash;
         *hashptr = hash;
 
 
     return found;
     return found;
 }
 }
 
 
-/* after lookup_dcache, the dentry is popped to prevent recycling */
-struct shim_dentry *
-lookup_dcache (struct shim_dentry * start, const char * name, int namelen,
-               const char * path, int pathlen, HASHTYPE * hashptr)
-{
-    lock(dcache_lock);
-    struct shim_dentry * dent = __lookup_dcache(start, name, namelen, path,
-                                                pathlen, hashptr);
-    unlock(dcache_lock);
-    return dent;
-}
-
-int __del_dentry_tree (struct shim_dentry * root)
-{
-    struct shim_dentry * this_parent = root;
-    struct shim_dentry * next;
-
-repeat:
-    next = this_parent->children.first;
-
-resume:
-    while (next != this_parent->children.first) {
-        struct shim_dentry *d, * tmp;
-        d = tmp = next;
-        next = tmp->siblings.next;
-        if (d->state & DENTRY_MOUNTPOINT) {
-            this_parent = d->mounted->root;
-            goto repeat;
-        }
-
-        if (!listp_empty(&d->children)) {
-            this_parent = d;
-            goto repeat;
-        }
-
-        __unset_parent_dentry(d, this_parent);
-        __del_dcache(d);
-    }
-
-    if (this_parent != root) {
-        struct shim_dentry * child = this_parent;
-        if (!this_parent->parent) {
-            this_parent = this_parent->fs->mount_point;
-            __del_dcache(child);
-            child = this_parent;
-        }
-        this_parent = this_parent->parent;
-        next = child->siblings.next;
-        __del_dcache(child);
-        __unset_parent_dentry(child, this_parent);
-        goto resume;
+/* This function recursively removes children and drops the reference count
+ * under root (but not the root itself).
+ *
+ * For memory-constrained systems (arguably SGX enclaves), there is a
+ * legitimate concern that this could overflow the stack, as a path can have
+ * as many as 4096 characters, leading to as many as 2048 stack frames.  It
+ * may be preferable to rewrite this using tail recursion or allocating a
+ * structure on the heap to track progress.
+ */
+int __del_dentry_tree(struct shim_dentry * root) {
+    struct shim_dentry *cursor, *n;
+
+    listp_for_each_entry_safe(cursor, n, &root->children, siblings) {
+        // Recur if this is a non-empty directory 
+        if (!listp_empty(&cursor->children))
+            __del_dentry_tree(cursor);
+
+        listp_del_init(cursor, &root->children, siblings);
+        cursor->parent = NULL;
+        root->nchildren--;
+        // Clear the hashed flag, in case there is any vestigial code based
+        //  on this state machine (where hased == valid).
+        cursor->state &= ~DENTRY_HASHED;
+        put_dentry(cursor);
     }
     }
 
 
     return 0;
     return 0;
@@ -509,7 +370,6 @@ END_CP_FUNC(dentry)
 BEGIN_RS_FUNC(dentry)
 BEGIN_RS_FUNC(dentry)
 {
 {
     struct shim_dentry * dent = (void *) (base + GET_CP_FUNC_ENTRY());
     struct shim_dentry * dent = (void *) (base + GET_CP_FUNC_ENTRY());
-    BEGIN_PROFILE_INTERVAL();
 
 
     CP_REBASE(dent->hlist);
     CP_REBASE(dent->hlist);
     CP_REBASE(dent->list);
     CP_REBASE(dent->list);
@@ -521,15 +381,19 @@ BEGIN_RS_FUNC(dentry)
 
 
     create_lock(dent->lock);
     create_lock(dent->lock);
 
 
-    if (dent->parent)
-        __set_parent_dentry(dent, dent->parent);
-
-    LISTP_TYPE(shim_dentry) * head = &dcache_htable[DCACHE_HASH(dent->rel_path.hash)];
-    listp_add(dent, head, hlist);
-    dent->state |= DENTRY_HASHED;
+    /* DEP 6/16/17: I believe the point of this line is to 
+     * fix up the children linked list.  Presumably the ref count and 
+     * child count is already correct in the checkpoint. */   
+    if (dent->parent) {
+        get_dentry(dent->parent);
+        get_dentry(dent);
+        listp_add_tail(dent, &dent->parent->children, siblings);
+    }
 
 
     DEBUG_RS("hash=%08x,path=%s,fs=%s", dent->rel_path.hash,
     DEBUG_RS("hash=%08x,path=%s,fs=%s", dent->rel_path.hash,
              dentry_get_path(dent, true, NULL),
              dentry_get_path(dent, true, NULL),
              dent->fs ? qstrgetstr(&dent->fs->path) : NULL);
              dent->fs ? qstrgetstr(&dent->fs->path) : NULL);
 }
 }
 END_RS_FUNC(dentry)
 END_RS_FUNC(dentry)
+
+

+ 158 - 36
LibOS/shim/src/fs/shim_fs.c

@@ -94,38 +94,55 @@ static struct shim_mount * alloc_mount (void)
 
 
 static bool mount_migrated = false;
 static bool mount_migrated = false;
 
 
-static int __mount_root (void)
+static int __mount_root (struct shim_dentry ** root)
 {
 {
-    int ret;
-    if ((ret = mount_fs("chroot", "file:", "/")) < 0) {
-        debug("mounting root filesystem failed (%e)\n", ret);
-        return ret;
+    char type[CONFIG_MAX], uri[CONFIG_MAX];
+    int ret = 0;
+
+    if (root_config &&
+            get_config(root_config, "fs.root.type", type, CONFIG_MAX) > 0 &&
+            get_config(root_config, "fs.root.uri", uri, CONFIG_MAX) > 0) {
+        debug("mounting root filesystem: %s from %s\n", type, uri);
+        if ((ret = mount_fs(type, uri, "/", NULL, root, 0)) < 0) {
+            debug("mounting root filesystem failed (%d)\n", ret);
+            goto out;
+        }
+        goto out;
     }
     }
-    return 0;
+
+    debug("mounting default root filesystem\n");
+    if ((ret = mount_fs("chroot", "file:", "/", NULL, root, 0)) < 0) {
+        debug("mounting root filesystem failed (%d)\n", ret);
+        goto out;
+    }
+
+out:
+    return ret;
 }
 }
 
 
-static int __mount_sys (void)
+static int __mount_sys (struct shim_dentry *root)
 {
 {
     int ret;
     int ret;
 
 
     debug("mounting as proc filesystem: /proc\n");
     debug("mounting as proc filesystem: /proc\n");
 
 
-    if ((ret = mount_fs("proc", NULL, "/proc")) < 0) {
-        debug("mounting proc filesystem failed (%e)\n", ret);
+    if ((ret = mount_fs("proc", NULL, "/proc", root, NULL, 0)) < 0) {
+        debug("mounting proc filesystem failed (%d)\n", ret);
         return ret;
         return ret;
     }
     }
 
 
     debug("mounting as dev filesystem: /dev\n");
     debug("mounting as dev filesystem: /dev\n");
 
 
-    if ((ret = mount_fs("dev", NULL, "/dev")) < 0) {
-        debug("mounting dev filesystem failed (%e)\n", ret);
+    struct shim_dentry *dev_dent = NULL;
+    if ((ret = mount_fs("dev", NULL, "/dev", root, &dev_dent, 0)) < 0) {
+        debug("mounting dev filesystem failed (%d)\n", ret);
         return ret;
         return ret;
     }
     }
 
 
     debug("mounting as chroot filesystem: from dev:tty to /dev\n");
     debug("mounting as chroot filesystem: from dev:tty to /dev\n");
 
 
-    if ((ret = mount_fs("chroot", "dev:tty", "/dev/tty")) < 0) {
-        debug("mounting terminal device failed (%e)\n", ret);
+    if ((ret = mount_fs("chroot", "dev:tty", "/dev/tty", dev_dent, NULL, 0)) < 0) {
+        debug("mounting terminal device failed (%d)\n", ret);
         return ret;
         return ret;
     }
     }
 
 
@@ -160,7 +177,7 @@ static int __mount_one_other (const char * key, int keylen)
 
 
     debug("mounting as %s filesystem: from %s to %s\n", t, uri, p);
     debug("mounting as %s filesystem: from %s to %s\n", t, uri, p);
 
 
-    if ((ret = mount_fs(t, uri, p)) < 0) {
+    if ((ret = mount_fs(t, uri, p, NULL, NULL, 1)) < 0) {
         debug("mounting %s on %s (type=%s) failed (%e)\n", uri, p, t,
         debug("mounting %s on %s (type=%s) failed (%e)\n", uri, p, t,
               -ret);
               -ret);
         return ret;
         return ret;
@@ -200,11 +217,12 @@ int init_mount_root (void)
         return 0;
         return 0;
 
 
     int ret;
     int ret;
-
-    if ((ret = __mount_root()) < 0)
+    struct shim_dentry *root = NULL;
+    
+    if ((ret = __mount_root(&root)) < 0)
         return ret;
         return ret;
 
 
-    if ((ret = __mount_sys()) < 0)
+    if ((ret = __mount_sys(root)) < 0)
         return ret;
         return ret;
 
 
     return 0;
     return 0;
@@ -262,22 +280,34 @@ int __mount_fs (struct shim_mount * mount, struct shim_dentry * dent)
     struct shim_dentry * mount_root = mount->root;
     struct shim_dentry * mount_root = mount->root;
 
 
     if (!mount_root) {
     if (!mount_root) {
-        mount_root = get_new_dentry(NULL, "", 0);
-        mount_root->fs = mount;
         /* mount_root->state |= DENTRY_VALID; */
         /* mount_root->state |= DENTRY_VALID; */
-        qstrsetstr(&mount_root->name, dentry_get_name(dent),
-                   dent->name.len);
-
-        if (mount->d_ops && mount->d_ops->lookup &&
-            (ret = mount->d_ops->lookup(mount_root, 0)) < 0 &&
-            ret != -ESKIPPED)
+        mount_root = get_new_dentry(mount, NULL, "", 0, NULL);
+        assert(mount->d_ops && mount->d_ops->lookup);
+        ret = mount->d_ops->lookup(mount_root, 0);
+        if (ret < 0) {
+            /* Try getting rid of ESKIPPED case */
+            assert (ret != -ESKIPPED);
             return ret;
             return ret;
-
+        }
         mount->root = mount_root;
         mount->root = mount_root;
     }
     }
 
 
-    mount_root->state |= dent->state & (DENTRY_REACHABLE|DENTRY_UNREACHABLE);
-    __add_dcache(mount_root, &mount->path.hash);
+    /* DEP 7/1/17: If the mount is a directory, make sure the mount
+     * point is marked as a directory */
+    if (mount_root->state & DENTRY_ISDIRECTORY)
+        dent->state |= DENTRY_ISDIRECTORY;
+    
+    /* DEP 6/16/17: In the dcache redesign, we don't use the *REACHABLE flags, but
+     * leaving this commented for documentation, in case there is a problem
+     * I over-simplified */
+    //mount_root->state |= dent->state & (DENTRY_REACHABLE|DENTRY_UNREACHABLE);
+
+    /* DEP 6/16/17: In the dcache redesign, I don't believe we need to manually
+     * rehash the path; this should be handled by get_new_dentry, or already be 
+     * hashed if mount_root exists.  I'm going to leave this line here for now
+     * as documentation in case there is a problem later.
+     */
+    //__add_dcache(mount_root, &mount->path.hash);
 
 
     if ((ret = __del_dentry_tree(dent)) < 0)
     if ((ret = __del_dentry_tree(dent)) < 0)
         return ret;
         return ret;
@@ -290,22 +320,32 @@ int __mount_fs (struct shim_mount * mount, struct shim_dentry * dent)
     do {
     do {
         struct shim_dentry * parent = dent->parent;
         struct shim_dentry * parent = dent->parent;
 
 
-        if (dent->state & DENTRY_ANCESTER) {
+        if (dent->state & DENTRY_ANCESTOR) {
             put_dentry(dent);
             put_dentry(dent);
             break;
             break;
         }
         }
 
 
-        dent->state |= DENTRY_ANCESTER;
+        dent->state |= DENTRY_ANCESTOR;
         if (parent)
         if (parent)
             get_dentry(parent);
             get_dentry(parent);
         put_dentry(dent);
         put_dentry(dent);
         dent = parent;
         dent = parent;
     } while (dent);
     } while (dent);
 
 
+    
     return 0;
     return 0;
 }
 }
 
 
-int mount_fs (const char * type, const char * uri, const char * mount_point)
+/* Parent is optional, but helpful.
+ * dentp (optional) memoizes the dentry of the newly-mounted FS, on success. 
+ *
+ * The make_ancestor flag creates pseudo-dentries for any missing paths (passed to
+ * __path_lookupat).  This is only intended for use to connect mounts specified in the manifest
+ * when an intervening path is missing.
+ */
+int mount_fs (const char * type, const char * uri, const char * mount_point,
+              struct shim_dentry *parent, struct shim_dentry **dentp,
+              int make_ancestor)
 {
 {
     int ret = 0;
     int ret = 0;
     struct shim_fs * fs = find_fs(type);
     struct shim_fs * fs = find_fs(type);
@@ -315,11 +355,47 @@ int mount_fs (const char * type, const char * uri, const char * mount_point)
         goto out;
         goto out;
     }
     }
 
 
-    lock(dcache_lock);
+    /* Split the mount point into the prefix and atom */
+    int mount_point_len = strlen(mount_point);
+    const char * last = &mount_point[mount_point_len - 1];
+    int left = mount_point_len;
+    int last_len = 1;
+    // Drop any trailing slashes
+    while (left && *last == '/') {
+        left--;
+        last--;
+        if (last_len != 0)
+            last_len--;
+    }
+    // Skip the atom
+    while (left && *last != '/') {
+        left--;
+        last--;
+        last_len++;
+    }
+    if (*last == '/') {
+        // Move forward one
+        last++;
+        last_len--;
+    }
 
 
-    struct shim_dentry * dent;
-    if ((ret = __path_lookupat(NULL, mount_point, 0, &dent)) < 0)
-        goto out;
+    if (!parent) {
+        // See if we are not at the root mount
+        if (mount_point_len != 1 || mount_point[0] != '/') {
+            // Look up the parent
+            char * parent_path = __alloca(mount_point_len);
+            memset(parent_path, 0, mount_point_len);
+            assert(last_len >= 1 && (mount_point_len - last_len) >= 0);
+            memcpy(parent_path, mount_point, mount_point_len - last_len);
+            if ((ret = __path_lookupat(dentry_root, parent_path, 0, &parent, 0,
+                                       dentry_root->fs, make_ancestor)) < 0) {
+                debug("Path lookup failed %d\n", ret);
+                goto out;
+            }
+        }
+    }
+    
+    lock(dcache_lock);
 
 
     struct shim_mount * mount = alloc_mount();
     struct shim_mount * mount = alloc_mount();
     void * mount_data = NULL;
     void * mount_data = NULL;
@@ -328,16 +404,62 @@ int mount_fs (const char * type, const char * uri, const char * mount_point)
     if ((ret = fs->fs_ops->mount(uri, mount_point, &mount_data)) < 0)
     if ((ret = fs->fs_ops->mount(uri, mount_point, &mount_data)) < 0)
         goto out;
         goto out;
 
 
+
     int uri_len = uri ? strlen(uri) : 0;
     int uri_len = uri ? strlen(uri) : 0;
-    qstrsetstr(&mount->path, mount_point, strlen(mount_point));
+    qstrsetstr(&mount->path, mount_point, mount_point_len);
     qstrsetstr(&mount->uri, uri, uri_len);
     qstrsetstr(&mount->uri, uri, uri_len);
     memcpy(mount->type, fs->name, sizeof(fs->name));
     memcpy(mount->type, fs->name, sizeof(fs->name));
     mount->fs_ops    = fs->fs_ops;
     mount->fs_ops    = fs->fs_ops;
     mount->d_ops     = fs->d_ops;
     mount->d_ops     = fs->d_ops;
     mount->data      = mount_data;
     mount->data      = mount_data;
+
+    /* Get the negative dentry from the cache, if one exists */
+    struct shim_dentry * dent, *dent2;
+    /* Special case the root */
+    if (mount_point_len == 1 && mount_point[0] == '/')
+        dent = dentry_root;
+    else {
+        dent = __lookup_dcache(parent, last,
+                               last_len,
+                               NULL, 0, NULL);
+
+        if(!dent) {
+            dent = get_new_dentry(mount, parent, last, last_len, NULL);
+            get_dentry(dent);
+        }
+    }
+    
+    assert(dent == dentry_root || !(dent->state & DENTRY_VALID));    
+
+    // We need to fix up the relative path to this mount, but only for
+    // directories.  
+    qstrsetstr(&dent->rel_path, "", 0);
     mount->path.hash = dent->rel_path.hash;
     mount->path.hash = dent->rel_path.hash;
 
 
+    /*Now go ahead and do a lookup so the dentry is valid */
+    if ((ret = __path_lookupat(dentry_root, mount_point, 0, &dent2, 0,
+                               parent ? parent->fs : mount, make_ancestor)) < 0) 
+        goto out;
+
+    assert(dent == dent2);
+
+    /* We want the net impact of mounting to increment the ref count on the
+     * entry (until the unmount).  But we shouldn't also hold the reference on
+     * dent from the validation step.  Drop it here */
+    put_dentry(dent2);
+    
     ret = __mount_fs(mount, dent);
     ret = __mount_fs(mount, dent);
+
+    // If we made it this far and the dentry is still negative, clear
+    // the negative flag from the denry. 
+    if ((!ret) && (dent->state & DENTRY_NEGATIVE)) 
+        dent->state &= ~DENTRY_NEGATIVE;
+    
+    /* Set the file system at the mount point properly */
+    dent->fs = mount;
+    
+    if (dentp && !ret)
+        *dentp = dent;
 out:
 out:
     unlock(dcache_lock);
     unlock(dcache_lock);
     return ret;
     return ret;

File diff suppressed because it is too large
+ 429 - 781
LibOS/shim/src/fs/shim_namei.c


+ 2 - 0
LibOS/shim/src/ipc/shim_ipc_nsimpl.h

@@ -544,6 +544,7 @@ int CONCAT3(del, NS, range) (IDTYPE idx)
     // Re-acquire the head; kind of ugly
     // Re-acquire the head; kind of ugly
     LISTP_TYPE(range) * head = range_table + RANGE_HASH(off);
     LISTP_TYPE(range) * head = range_table + RANGE_HASH(off);
     listp_del(r, head, hlist);
     listp_del(r, head, hlist);
+
     /* Chia-Che Tsai 10/17/17: only when r->owner is non-NULL,
     /* Chia-Che Tsai 10/17/17: only when r->owner is non-NULL,
      * and r->owner->vmid == cur_process.vmid, r is on the
      * and r->owner->vmid == cur_process.vmid, r is on the
      * owned list, otherwise it is an offered. */
      * owned list, otherwise it is an offered. */
@@ -551,6 +552,7 @@ int CONCAT3(del, NS, range) (IDTYPE idx)
         listp_del(r, &owned_ranges, list);
         listp_del(r, &owned_ranges, list);
     else
     else
         listp_del(r, &offered_ranges, list);
         listp_del(r, &offered_ranges, list);
+
     put_ipc_info(r->owner);
     put_ipc_info(r->owner);
     free(r);
     free(r);
 
 

+ 4 - 2
LibOS/shim/src/shim_checkpoint.c

@@ -634,7 +634,9 @@ int init_from_checkpoint_file (const char * filename,
     struct shim_dentry * dir = NULL;
     struct shim_dentry * dir = NULL;
     int ret;
     int ret;
 
 
-    ret = path_lookupat(NULL, filename, LOOKUP_ACCESS|LOOKUP_DIRECTORY, &dir);
+    /* XXX: Not sure what to do here yet */
+    assert(0);
+    ret = path_lookupat(NULL, filename, LOOKUP_ACCESS|LOOKUP_DIRECTORY, &dir, NULL);
     if (ret < 0)
     if (ret < 0)
         return ret;
         return ret;
 
 
@@ -654,7 +656,7 @@ int init_from_checkpoint_file (const char * filename,
     for ( ; d ; d = d->next) {
     for ( ; d ; d = d->next) {
         struct shim_dentry * file;
         struct shim_dentry * file;
         if ((ret = lookup_dentry(dir, d->name, strlen(d->name), false,
         if ((ret = lookup_dentry(dir, d->name, strlen(d->name), false,
-                                 &file)) < 0)
+                                 &file, dir->fs)) < 0)
             continue;
             continue;
         if (file->state & DENTRY_NEGATIVE)
         if (file->state & DENTRY_NEGATIVE)
             continue;
             continue;

+ 2 - 2
LibOS/shim/src/sys/shim_access.c

@@ -43,7 +43,7 @@ int shim_do_access (const char * file, mode_t mode)
     struct shim_dentry * dent = NULL;
     struct shim_dentry * dent = NULL;
     int ret = 0;
     int ret = 0;
 
 
-    ret = path_lookupat(NULL, file, LOOKUP_ACCESS|LOOKUP_FOLLOW, &dent);
+    ret = path_lookupat(NULL, file, LOOKUP_ACCESS|LOOKUP_FOLLOW, &dent, NULL);
     if (!ret)
     if (!ret)
         ret = permission(dent, mode, 1);
         ret = permission(dent, mode, 1);
 
 
@@ -64,7 +64,7 @@ int shim_do_faccessat (int dfd, const char * filename, mode_t mode)
     if ((ret = path_startat(dfd, &dir)) < 0)
     if ((ret = path_startat(dfd, &dir)) < 0)
         return ret;
         return ret;
 
 
-    ret = path_lookupat(dir, filename, LOOKUP_ACCESS|LOOKUP_FOLLOW, &dent);
+    ret = path_lookupat(dir, filename, LOOKUP_ACCESS|LOOKUP_FOLLOW, &dent, NULL);
     if (ret < 0)
     if (ret < 0)
         goto out;
         goto out;
 
 

+ 3 - 1
LibOS/shim/src/sys/shim_exec.c

@@ -234,7 +234,9 @@ int shim_do_execve (const char * file, const char ** argv,
 
 
 reopen:
 reopen:
 
 
-    if ((ret = path_lookupat(NULL, file, LOOKUP_OPEN, &dent)) < 0)
+    /* XXX: Not sure what to do here yet */
+    assert(cur_thread);
+    if ((ret = path_lookupat(NULL, file, LOOKUP_OPEN, &dent, NULL)) < 0)
         return ret;
         return ret;
 
 
     struct shim_mount * fs = dent->fs;
     struct shim_mount * fs = dent->fs;

+ 22 - 13
LibOS/shim/src/sys/shim_fs.c

@@ -52,7 +52,7 @@ int shim_do_unlink (const char * file)
     struct shim_dentry * dent = NULL;
     struct shim_dentry * dent = NULL;
     int ret = 0;
     int ret = 0;
 
 
-    if ((ret = path_lookupat(NULL, file, LOOKUP_OPEN, &dent)) < 0)
+    if ((ret = path_lookupat(NULL, file, LOOKUP_OPEN, &dent, NULL)) < 0)
         return ret;
         return ret;
 
 
     if (!dent->parent)
     if (!dent->parent)
@@ -88,7 +88,7 @@ int shim_do_unlinkat (int dfd, const char * pathname, int flag)
     if ((ret = path_startat(dfd, &dir)) < 0)
     if ((ret = path_startat(dfd, &dir)) < 0)
         return ret;
         return ret;
 
 
-    if ((ret = path_lookupat(dir, pathname, LOOKUP_OPEN, &dent)) < 0)
+    if ((ret = path_lookupat(dir, pathname, LOOKUP_OPEN, &dent, NULL)) < 0)
         goto out;
         goto out;
 
 
     if (!dent->parent) {
     if (!dent->parent) {
@@ -155,7 +155,7 @@ int shim_do_rmdir (const char * pathname)
     struct shim_dentry * dent = NULL;
     struct shim_dentry * dent = NULL;
 
 
     if ((ret = path_lookupat(NULL, pathname, LOOKUP_OPEN|LOOKUP_DIRECTORY,
     if ((ret = path_lookupat(NULL, pathname, LOOKUP_OPEN|LOOKUP_DIRECTORY,
-                             &dent)) < 0)
+                             &dent, NULL)) < 0)
         return ret;
         return ret;
 
 
     if (!dent->parent) {
     if (!dent->parent) {
@@ -197,7 +197,7 @@ int shim_do_chmod (const char * path, mode_t mode)
     struct shim_dentry * dent = NULL;
     struct shim_dentry * dent = NULL;
     int ret = 0;
     int ret = 0;
 
 
-    if ((ret = path_lookupat(NULL, path, LOOKUP_OPEN, &dent)) < 0)
+    if ((ret = path_lookupat(NULL, path, LOOKUP_OPEN, &dent, NULL)) < 0)
         return ret;
         return ret;
 
 
     if (dent->fs && dent->fs->d_ops &&
     if (dent->fs && dent->fs->d_ops &&
@@ -227,7 +227,7 @@ int shim_do_fchmodat (int dfd, const char * filename, mode_t mode)
     if ((ret = path_startat(dfd, &dir)) < 0)
     if ((ret = path_startat(dfd, &dir)) < 0)
         return ret;
         return ret;
 
 
-    if ((ret = path_lookupat(dir, filename, LOOKUP_OPEN, &dent)) < 0)
+    if ((ret = path_lookupat(dir, filename, LOOKUP_OPEN, &dent, NULL)) < 0)
         goto out;
         goto out;
 
 
     if (dent->fs && dent->fs->d_ops &&
     if (dent->fs && dent->fs->d_ops &&
@@ -272,7 +272,7 @@ int shim_do_chown (const char * path, uid_t uid, gid_t gid)
     struct shim_dentry * dent = NULL;
     struct shim_dentry * dent = NULL;
     int ret = 0;
     int ret = 0;
 
 
-    if ((ret = path_lookupat(NULL, path, LOOKUP_OPEN, &dent)) < 0)
+    if ((ret = path_lookupat(NULL, path, LOOKUP_OPEN, &dent, NULL)) < 0)
         return ret;
         return ret;
 
 
     /* XXX: do nothing now */
     /* XXX: do nothing now */
@@ -295,7 +295,7 @@ int shim_do_fchownat (int dfd, const char * filename, uid_t uid, gid_t gid,
     if ((ret = path_startat(dfd, &dir)) < 0)
     if ((ret = path_startat(dfd, &dir)) < 0)
         return ret;
         return ret;
 
 
-    if ((ret = path_lookupat(dir, filename, LOOKUP_OPEN, &dent)) < 0)
+    if ((ret = path_lookupat(dir, filename, LOOKUP_OPEN, &dent, NULL)) < 0)
         goto out;
         goto out;
 
 
     /* XXX: do nothing now */
     /* XXX: do nothing now */
@@ -666,7 +666,7 @@ int shim_do_rename (const char * oldname, const char * newname)
     struct shim_dentry * old_dent = NULL, * new_dent = NULL;
     struct shim_dentry * old_dent = NULL, * new_dent = NULL;
     int ret = 0;
     int ret = 0;
 
 
-    if ((ret = path_lookupat(NULL, oldname, LOOKUP_OPEN, &old_dent)) < 0)
+    if ((ret = path_lookupat(NULL, oldname, LOOKUP_OPEN, &old_dent, NULL)) < 0) 
         goto out;
         goto out;
 
 
     if (old_dent->state & DENTRY_NEGATIVE) {
     if (old_dent->state & DENTRY_NEGATIVE) {
@@ -675,9 +675,17 @@ int shim_do_rename (const char * oldname, const char * newname)
     }
     }
 
 
     if ((ret = path_lookupat(NULL, newname, LOOKUP_OPEN|LOOKUP_CREATE,
     if ((ret = path_lookupat(NULL, newname, LOOKUP_OPEN|LOOKUP_CREATE,
-                             &new_dent)) < 0)
-        goto out;
+                             &new_dent, NULL)) < 0) {
+        // It is now ok for pathlookupat to return ENOENT with a negative DETRY
+        if (!(ret == -ENOENT && new_dent
+              && (new_dent->state & (DENTRY_NEGATIVE|DENTRY_VALID))))
+            goto out;
+    }
 
 
+    // Both dentries should have a ref count of at least 2 at this point
+    assert(REF_GET(old_dent->ref_count) >= 2);
+    assert(REF_GET(new_dent->ref_count) >= 2);
+    
     ret = do_rename(old_dent, new_dent);
     ret = do_rename(old_dent, new_dent);
 
 
 out:
 out:
@@ -685,6 +693,7 @@ out:
         put_dentry(old_dent);
         put_dentry(old_dent);
     if (new_dent)
     if (new_dent)
         put_dentry(new_dent);
         put_dentry(new_dent);
+
     return ret;
     return ret;
 }
 }
 
 
@@ -699,7 +708,7 @@ int shim_do_renameat (int olddfd, const char * pathname, int newdfd,
         goto out;
         goto out;
 
 
 
 
-    if ((ret = path_lookupat(old_dir, pathname, LOOKUP_OPEN, &old_dent)) < 0)
+    if ((ret = path_lookupat(old_dir, pathname, LOOKUP_OPEN, &old_dent, NULL)) < 0)
         goto out;
         goto out;
 
 
     if (old_dent->state & DENTRY_NEGATIVE) {
     if (old_dent->state & DENTRY_NEGATIVE) {
@@ -711,7 +720,7 @@ int shim_do_renameat (int olddfd, const char * pathname, int newdfd,
         goto out;
         goto out;
 
 
     if ((ret = path_lookupat(new_dir, newname, LOOKUP_OPEN|LOOKUP_CREATE,
     if ((ret = path_lookupat(new_dir, newname, LOOKUP_OPEN|LOOKUP_CREATE,
-                             &new_dent)) < 0)
+                             &new_dent, NULL)) < 0)
         goto out;
         goto out;
 
 
     ret = do_rename(old_dent, new_dent);
     ret = do_rename(old_dent, new_dent);
@@ -767,7 +776,7 @@ int shim_do_chroot (const char * filename)
 {
 {
     int ret = 0;
     int ret = 0;
     struct shim_dentry * dent = NULL;
     struct shim_dentry * dent = NULL;
-    if ((ret = path_lookupat(NULL, filename, 0 , &dent)) < 0)
+    if ((ret = path_lookupat(NULL, filename, 0 , &dent, NULL)) < 0)
         goto out;
         goto out;
 
 
     if (!dent) {
     if (!dent) {

+ 1 - 1
LibOS/shim/src/sys/shim_getcwd.c

@@ -70,7 +70,7 @@ int shim_do_chdir (const char * filename)
     struct shim_dentry * dent = NULL;
     struct shim_dentry * dent = NULL;
     int ret;
     int ret;
 
 
-    if ((ret = path_lookupat(NULL, filename, LOOKUP_OPEN, &dent)) < 0)
+    if ((ret = path_lookupat(NULL, filename, LOOKUP_OPEN, &dent, NULL)) < 0)
         return ret;
         return ret;
 
 
     if (!dent)
     if (!dent)

+ 27 - 5
LibOS/shim/src/sys/shim_open.c

@@ -336,6 +336,12 @@ size_t shim_do_getdents (int fd, struct linux_dirent * buf, size_t count)
     struct linux_dirent * b = buf;
     struct linux_dirent * b = buf;
     int bytes = 0;
     int bytes = 0;
 
 
+    /* If we haven't listed the directory, do this first */
+    if (!(dent->state & DENTRY_LISTED)) {
+        ret = list_directory_dentry(dent);
+        if (ret) goto out;
+    }
+
 #define DIRENT_SIZE(len)  (sizeof(struct linux_dirent) +                \
 #define DIRENT_SIZE(len)  (sizeof(struct linux_dirent) +                \
                            sizeof(struct linux_dirent_tail) + (len) + 1)
                            sizeof(struct linux_dirent_tail) + (len) + 1)
 
 
@@ -374,6 +380,11 @@ size_t shim_do_getdents (int fd, struct linux_dirent * buf, size_t count)
         dirhdl->dotdot = NULL;
         dirhdl->dotdot = NULL;
     }
     }
 
 
+    if (dirhdl->ptr == (void *) -1) {
+        ret = list_directory_handle(dent, hdl);
+        if (ret) goto out;
+    }
+    
     while (dirhdl->ptr && *dirhdl->ptr) {
     while (dirhdl->ptr && *dirhdl->ptr) {
         dent = *dirhdl->ptr;
         dent = *dirhdl->ptr;
         /* DEP 3/3/17: We need to filter negative dentries */
         /* DEP 3/3/17: We need to filter negative dentries */
@@ -390,8 +401,8 @@ done:
     ret = bytes;
     ret = bytes;
     /* DEP 3/3/17: Properly detect EINVAL case, where buffer is too small to
     /* DEP 3/3/17: Properly detect EINVAL case, where buffer is too small to
      * hold anything */
      * hold anything */
-    if (bytes == 0 && ((dirhdl->ptr && *dirhdl->ptr)
-                       || dirhdl->dotdot || dirhdl->dot))
+    if (bytes == 0 && (dirhdl->dot || dirhdl->dotdot || 
+                       (dirhdl->ptr && *dirhdl->ptr)))
         ret = -EINVAL;
         ret = -EINVAL;
     unlock(hdl->lock);
     unlock(hdl->lock);
 out:
 out:
@@ -425,6 +436,12 @@ size_t shim_do_getdents64 (int fd, struct linux_dirent64 * buf, size_t count)
     struct linux_dirent64 * b = buf;
     struct linux_dirent64 * b = buf;
     int bytes = 0;
     int bytes = 0;
 
 
+    /* If we haven't listed the directory, do this first */
+    if (!(dent->state & DENTRY_LISTED)) {
+        ret = list_directory_dentry(dent);
+        if (ret) goto out;
+    }
+    
 #define DIRENT_SIZE(len)  (sizeof(struct linux_dirent64) + (len) + 1)
 #define DIRENT_SIZE(len)  (sizeof(struct linux_dirent64) + (len) + 1)
 
 
 #define ASSIGN_DIRENT(dent, name, type)                                 \
 #define ASSIGN_DIRENT(dent, name, type)                                 \
@@ -456,6 +473,11 @@ size_t shim_do_getdents64 (int fd, struct linux_dirent64 * buf, size_t count)
         dirhdl->dotdot = NULL;
         dirhdl->dotdot = NULL;
     }
     }
 
 
+    if (dirhdl->ptr == (void *) -1) {
+        ret = list_directory_handle(dent, hdl);
+        if (ret) goto out;
+    }
+    
     while (dirhdl->ptr && *dirhdl->ptr) {
     while (dirhdl->ptr && *dirhdl->ptr) {
         dent = *dirhdl->ptr;
         dent = *dirhdl->ptr;
         /* DEP 3/3/17: We need to filter negative dentries */
         /* DEP 3/3/17: We need to filter negative dentries */
@@ -472,8 +494,8 @@ done:
     ret = bytes;
     ret = bytes;
     /* DEP 3/3/17: Properly detect EINVAL case, where buffer is too small to
     /* DEP 3/3/17: Properly detect EINVAL case, where buffer is too small to
      * hold anything */
      * hold anything */
-    if (bytes == 0 && ((dirhdl->ptr && *dirhdl->ptr)
-                       || dirhdl->dotdot || dirhdl->dot))
+    if (bytes == 0 && (dirhdl->dot || dirhdl->dotdot || 
+                       (dirhdl->ptr && *dirhdl->ptr)))
         ret = -EINVAL;
         ret = -EINVAL;
     unlock(hdl->lock);
     unlock(hdl->lock);
 out:
 out:
@@ -521,7 +543,7 @@ int shim_do_truncate (const char * path, loff_t length)
     struct shim_dentry * dent = NULL;
     struct shim_dentry * dent = NULL;
     int ret = 0;
     int ret = 0;
 
 
-    if ((ret = path_lookupat(NULL, path, 0, &dent)) < 0)
+    if ((ret = path_lookupat(NULL, path, 0, &dent, NULL)) < 0)
         return ret;
         return ret;
 
 
     struct shim_mount * fs = dent->fs;
     struct shim_mount * fs = dent->fs;

+ 1 - 1
LibOS/shim/src/sys/shim_sandbox.c

@@ -60,7 +60,7 @@ static int isolate_fs (struct config_store * cfg, const char * path)
     struct shim_dentry * dent = NULL;
     struct shim_dentry * dent = NULL;
     int ret = 0;
     int ret = 0;
 
 
-    if ((ret = path_lookupat(NULL, path, LOOKUP_OPEN, &dent)) < 0)
+    if ((ret = path_lookupat(NULL, path, LOOKUP_OPEN, &dent, NULL)) < 0)
         return ret;
         return ret;
 
 
     if (!(dent->state & DENTRY_ISDIRECTORY)) {
     if (!(dent->state & DENTRY_ISDIRECTORY)) {

+ 8 - 4
LibOS/shim/src/sys/shim_socket.c

@@ -470,9 +470,13 @@ int shim_do_bind (int sockfd, struct sockaddr * addr, socklen_t addrlen)
         char * spath = saddr->sun_path;
         char * spath = saddr->sun_path;
         struct shim_dentry * dent = NULL;
         struct shim_dentry * dent = NULL;
 
 
-        if ((ret = path_lookupat(NULL, spath, LOOKUP_CREATE, &dent)) < 0) 
-            goto out;
-
+        if ((ret = path_lookupat(NULL, spath, LOOKUP_CREATE, &dent, NULL)) < 0) {
+            // DEP 7/3/17: We actually want either 0 or -ENOENT, as the
+            // expected case is that the name is free (and we get the dent to
+            // populate the name)
+            if (ret != -ENOENT || !dent)
+                goto out;
+        }
 
 
         if (dent->state & DENTRY_VALID &&
         if (dent->state & DENTRY_VALID &&
             !(dent->state & DENTRY_NEGATIVE)) {
             !(dent->state & DENTRY_NEGATIVE)) {
@@ -720,7 +724,7 @@ int shim_do_connect (int sockfd, struct sockaddr * addr, int addrlen)
         char * spath = saddr->sun_path;
         char * spath = saddr->sun_path;
         struct shim_dentry * dent;
         struct shim_dentry * dent;
 
 
-        if ((ret = path_lookupat(NULL, spath, LOOKUP_CREATE, &dent)) < 0)
+        if ((ret = path_lookupat(NULL, spath, LOOKUP_CREATE, &dent, NULL)) < 0)
             goto out;
             goto out;
 
 
         struct shim_unix_data * data = dent->data;
         struct shim_unix_data * data = dent->data;

+ 48 - 3
LibOS/shim/src/sys/shim_stat.c

@@ -42,7 +42,7 @@ int shim_do_stat (const char * file, struct stat * stat)
     int ret;
     int ret;
     struct shim_dentry * dent = NULL;
     struct shim_dentry * dent = NULL;
 
 
-    if ((ret = path_lookupat(NULL, file, LOOKUP_ACCESS|LOOKUP_FOLLOW, &dent)) < 0)
+    if ((ret = path_lookupat(NULL, file, LOOKUP_ACCESS|LOOKUP_FOLLOW, &dent, NULL)) < 0)
         goto out;
         goto out;
 
 
     struct shim_mount * fs = dent->fs;
     struct shim_mount * fs = dent->fs;
@@ -67,7 +67,7 @@ int shim_do_lstat (const char * file, struct stat * stat)
     int ret;
     int ret;
     struct shim_dentry * dent = NULL;
     struct shim_dentry * dent = NULL;
 
 
-    if ((ret = path_lookupat(NULL, file, LOOKUP_ACCESS, &dent)) < 0)
+    if ((ret = path_lookupat(NULL, file, LOOKUP_ACCESS, &dent, NULL)) < 0)
         goto out;
         goto out;
 
 
     struct shim_mount * fs = dent->fs;
     struct shim_mount * fs = dent->fs;
@@ -117,7 +117,7 @@ int shim_do_readlink (const char * file, char * buf, int bufsize)
     struct shim_dentry * dent = NULL;
     struct shim_dentry * dent = NULL;
     struct shim_qstr qstr = QSTR_INIT;
     struct shim_qstr qstr = QSTR_INIT;
 
 
-    if ((ret = path_lookupat(NULL, file, LOOKUP_ACCESS, &dent)) < 0)
+    if ((ret = path_lookupat(NULL, file, LOOKUP_ACCESS, &dent, NULL)) < 0)
         return ret;
         return ret;
 
 
     ret = -EINVAL;
     ret = -EINVAL;
@@ -143,3 +143,48 @@ out:
     put_dentry(dent);
     put_dentry(dent);
     return ret;
     return ret;
 }
 }
+
+static int __do_statfs (struct shim_mount * fs, struct statfs * buf)
+{
+    if (!buf)
+        return -EFAULT;
+
+    memset(buf, 0, sizeof(*buf));
+
+    buf->f_bsize = 4096;
+    buf->f_blocks = 20000000;
+    buf->f_bfree = 10000000;
+    buf->f_bavail = 10000000;
+
+    debug("statfs: %ld %ld %ld\n", buf->f_blocks, buf->f_bfree,
+            buf->f_bavail);
+
+    return 0;
+}
+
+int shim_do_statfs (const char * path, struct statfs * buf)
+{
+    if (!path)
+        return -EFAULT;
+
+    int ret;
+    struct shim_dentry * dent = NULL;
+
+    if ((ret = path_lookupat(NULL, path, LOOKUP_ACCESS|LOOKUP_FOLLOW, &dent, NULL)) < 0)
+        return ret;
+
+    struct shim_mount * fs = dent->fs;
+    put_dentry(dent);
+    return __do_statfs (fs, buf);
+}
+
+int shim_do_fstatfs (int fd, struct statfs * buf)
+{
+    struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL);
+    if (!hdl)
+        return -EBADF;
+
+    struct shim_mount * fs = hdl->fs;
+    put_handle(hdl);
+    return __do_statfs (fs, buf);
+}

+ 1 - 1
LibOS/shim/test/apps/lmbench/Makefile

@@ -70,7 +70,7 @@ regression: all
 	cp -f lmbench-regression $(LMBENCHDIR)/bin/linux
 	cp -f lmbench-regression $(LMBENCHDIR)/bin/linux
 	cd $(LMBENCHDIR)/bin/linux && \
 	cd $(LMBENCHDIR)/bin/linux && \
 		env LOADER=./pal_loader OS=linux \
 		env LOADER=./pal_loader OS=linux \
-		./lmbench-regression
+		./lmbench-regression 
 
 
 clean-lmbench:
 clean-lmbench:
 	$(MAKE) -C $(LMBENCHDIR) clean
 	$(MAKE) -C $(LMBENCHDIR) clean

+ 0 - 1
LibOS/shim/test/apps/ltp/BLOCKED

@@ -1,4 +1,3 @@
-chdir01
 chdir04
 chdir04
 epoll_wait01
 epoll_wait01
 fcntl15
 fcntl15

+ 12 - 0
LibOS/shim/test/apps/ltp/PASSED

@@ -16,6 +16,7 @@ asyncio02,4
 asyncio02,5
 asyncio02,5
 asyncio02,6
 asyncio02,6
 brk01,1
 brk01,1
+chdir01,1
 chmod01,1
 chmod01,1
 chmod01,2
 chmod01,2
 chmod01,3
 chmod01,3
@@ -33,6 +34,7 @@ chmod02,6
 chmod02,7
 chmod02,7
 chmod02,8
 chmod02,8
 chmod03,1
 chmod03,1
+chmod04,1
 chown01,1
 chown01,1
 chroot02,1
 chroot02,1
 clock_getres01,2
 clock_getres01,2
@@ -177,6 +179,10 @@ fstat01,1
 fstat01_64,1
 fstat01_64,1
 fstat03,1
 fstat03,1
 fstat03_64,1
 fstat03_64,1
+fstatat01,2
+fstatat01,4
+fstatat01,5
+fstatat01,6
 fsync01,1
 fsync01,1
 fsync03,1
 fsync03,1
 ftruncate01,1
 ftruncate01,1
@@ -277,6 +283,11 @@ memcpy01,3
 memset01,1
 memset01,1
 memset01,2
 memset01,2
 mkdir08,1
 mkdir08,1
+mkdirat01,1
+mkdirat01,2
+mkdirat01,3
+mkdirat01,4
+mkdirat01,5
 mlock03,1
 mlock03,1
 mmap001,1
 mmap001,1
 mmap001,2
 mmap001,2
@@ -306,6 +317,7 @@ munmap02,1
 nanosleep01,1
 nanosleep01,1
 nanosleep03,1
 nanosleep03,1
 newuname01,1
 newuname01,1
+open01,2
 open03,1
 open03,1
 open09,1
 open09,1
 open09,2
 open09,2

+ 4 - 1
LibOS/shim/test/apps/ltp/TIMEOUTS

@@ -2,6 +2,7 @@ testcase,timeout
 alarm01,5
 alarm01,5
 alarm06,16
 alarm06,16
 clone05,30
 clone05,30
+exit01,40
 faccessat01,80
 faccessat01,80
 fchdir02,40
 fchdir02,40
 fchmod07,40
 fchmod07,40
@@ -22,15 +23,17 @@ pread01,40
 pread02,40
 pread02,40
 preadv01,40
 preadv01,40
 read01,40
 read01,40
+readdir01,40
 readv01,40
 readv01,40
 sendfile03_64,40
 sendfile03_64,40
 setuid02,40
 setuid02,40
+sockioctl01,40
 sigaltstack02,40
 sigaltstack02,40
 socket01,40
 socket01,40
 socket02,40
 socket02,40
 stat05_64,40
 stat05_64,40
 syscall01,80
 syscall01,80
 wait401,40
 wait401,40
-waitpid03,40
+waitpid03,80
 waitpid05,160
 waitpid05,160
 write03,40
 write03,40

+ 14 - 4
LibOS/shim/test/regression/30_mmap.py

@@ -4,20 +4,30 @@ import os, sys, mmap
 from regression import Regression
 from regression import Regression
 
 
 loader = sys.argv[1]
 loader = sys.argv[1]
+try:
+    sgx = os.environ['SGX_RUN']
+except KeyError:
+    sgx = False
 
 
 # Running Bootstrap
 # Running Bootstrap
 regression = Regression(loader, "mmap-file", None, 60000)
 regression = Regression(loader, "mmap-file", None, 60000)
 
 
 regression.add_check(name="Private mmap beyond file range",
 regression.add_check(name="Private mmap beyond file range",
     check=lambda res: "mmap test 6 passed" in res[0].out and \
     check=lambda res: "mmap test 6 passed" in res[0].out and \
-                      "mmap test 7 passed" in res[0].out and \
-                      "mmap test 8 passed" in res[0].out)
+                      "mmap test 7 passed" in res[0].out)
 
 
 regression.add_check(name="Private mmap beyond file range (after fork)",
 regression.add_check(name="Private mmap beyond file range (after fork)",
     check=lambda res: "mmap test 1 passed" in res[0].out and \
     check=lambda res: "mmap test 1 passed" in res[0].out and \
                       "mmap test 2 passed" in res[0].out and \
                       "mmap test 2 passed" in res[0].out and \
                       "mmap test 3 passed" in res[0].out and \
                       "mmap test 3 passed" in res[0].out and \
-                      "mmap test 4 passed" in res[0].out and \
-                      "mmap test 5 passed" in res[0].out)
+                      "mmap test 4 passed" in res[0].out)
 
 
+# On SGX, SIGBUS isn't always implemented correctly, for lack
+# of memory protection.  For now, some of these cases won't work.
+if not sgx:
+    regression.add_check(name="SIGBUS test",
+                         check=lambda res: "mmap test 5 passed" in res[0].out and \
+                         "mmap test 8 passed" in res[0].out)
+
+                         
 regression.run_checks()
 regression.run_checks()

+ 0 - 1
Pal/lib/crypto/adapters/mbedtls_adapter.c

@@ -195,4 +195,3 @@ int lib_RSAFreeKey(LIB_RSA_KEY *key)
     mbedtls_rsa_free(key);
     mbedtls_rsa_free(key);
     return 0;
     return 0;
 }
 }
-

Some files were not shown because too many files changed in this diff