Hook NFS proxy together with BlueSky core.
authorMichael Vrable <mvrable@cs.ucsd.edu>
Fri, 21 Aug 2009 16:58:44 +0000 (09:58 -0700)
committerMichael Vrable <mvrable@turin.ucsd.edu>
Fri, 21 Aug 2009 16:58:44 +0000 (09:58 -0700)
.gitignore
Makefile
bluesky.h
dir.c
inode.c
main.c
nfs3/Makefile
nfs3/mount.c
nfs3/nfs3.c
nfs3/nfsd.c

index 5761abc..827a703 100644 (file)
@@ -1 +1,2 @@
 *.o
+bluesky.a
index 386cc23..7f5b123 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -3,11 +3,19 @@ DEBUG=-g
 CFLAGS=-O -Wall -D_FILE_OFFSET_BITS=64 $(DEBUG) \
        $(shell pkg-config --cflags $(PACKAGES))
 LDFLAGS=$(DEBUG) $(shell pkg-config --libs $(PACKAGES))
+SUBDIRS=nfs3
 
-SRCS=dir.c inode.c main.c
+SRCS=dir.c inode.c
 OBJS=$(SRCS:.c=.o)
 
-bluesky : $(OBJS)
+all : bluesky
+       for d in $(SUBDIRS); do $(MAKE) -C $$d; done
+
+bluesky.a : $(OBJS)
+       $(AR) -r $@ $(OBJS)
+       ranlib $@
+
+bluesky : main.o bluesky.a
        $(CC) $(LDFLAGS) -o $@ $^
 
 clean :
@@ -17,6 +25,6 @@ dep :
        touch Makefile.dep
        makedepend -fMakefile.dep $(SRCS)
 
-.PHONY : clean dep
+.PHONY : all clean dep
 
 -include *.dep
index 068173f..40c989b 100644 (file)
--- a/bluesky.h
+++ b/bluesky.h
@@ -14,8 +14,7 @@
 
 /* File types.  The numeric values are chosen to match with those used in
  * NFSv3. */
-enum BlueSkyFileType {
-    BLUESKY_INVALID = 0,
+typedef enum {
     BLUESKY_REGULAR = 1,
     BLUESKY_DIRECTORY = 2,
     BLUESKY_BLOCK = 3,
@@ -23,7 +22,7 @@ enum BlueSkyFileType {
     BLUESKY_SYMLINK = 5,
     BLUESKY_SOCKET = 6,
     BLUESKY_FIFO = 7,
-};
+} BlueSkyFileType;
 
 /* Filesystem state.  Each filesystem which is exported is represented by a
  * single bluesky_fs structure in memory. */
@@ -35,6 +34,9 @@ typedef struct {
     uint64_t next_inum;         /* Next available inode for allocation */
 } BlueSkyFS;
 
+/* Inode number of the root directory. */
+#define BLUESKY_ROOT_INUM 1
+
 /* Timestamp, measured in microseconds since the Unix epoch. */
 typedef int64_t bluesky_time;
 
@@ -45,7 +47,7 @@ typedef struct {
     gint refcnt;                /* May be accessed atomically without lock */
     GMutex *lock;
 
-    int type;
+    BlueSkyFileType type;
     uint32_t mode;
     uint32_t uid, gid;
     uint32_t nlink;
@@ -66,6 +68,7 @@ typedef struct {
 
     /* Directory-specific fields */
     GSequence *dirents;
+    uint64_t parent_inum;       /* inode for ".."; 0 if the root directory */
 } BlueSkyInode;
 
 /* A directory entry.  The name is UTF-8 and is a freshly-allocated string.
@@ -80,7 +83,10 @@ typedef struct {
 
 int64_t bluesky_get_current_time();
 uint64_t bluesky_fs_alloc_inode(BlueSkyFS *fs);
-BlueSkyInode *bluesky_new_inode(uint64_t inum);
+BlueSkyInode *bluesky_new_inode(uint64_t inum, BlueSkyFileType type);
+
+BlueSkyInode *bluesky_get_inode(BlueSkyFS *fs, uint64_t inum);
+void bluesky_insert_inode(BlueSkyFS *fs, BlueSkyInode *inode);
 
 void bluesky_dirent_destroy(gpointer dirent);
 uint64_t bluesky_directory_hash(gchar *name);
diff --git a/dir.c b/dir.c
index c4cbec2..eab71be 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -16,7 +16,8 @@
 /* Hash a filename for a directory lookup.  The string is hashed to a 64-bit
  * value.  It is guaranteed that the hash values 0, 1, and 2 are never returned
  * (to allow the hash value to be used as an NFS cookie for a READDIR
- * operation). */
+ * operation).  TODO: We perhaps should make this a keyed hash, and may want to
+ * use something cheaper than MD5 to compute. */
 uint64_t bluesky_directory_hash(gchar *name)
 {
     GChecksum *csum = g_checksum_new(G_CHECKSUM_MD5);
@@ -73,17 +74,22 @@ uint64_t bluesky_directory_lookup(BlueSkyInode *inode, gchar *name)
     BlueSkyDirent d = {name, hash, 0};
     GSequenceIter *i = g_sequence_search(inode->dirents, &d,
                                          bluesky_dirent_compare, NULL);
+
+    /* g_sequence_search will return an iterator pointing just beyond the
+     * desired node if there is a match, so that when inserting the new node
+     * will go after the match.  But we are trying to do a lookup, so back up
+     * by one position. */
     i = g_sequence_iter_prev(i);
 
     if (g_sequence_iter_is_end(i))
         return 0;
     BlueSkyDirent *dirent = g_sequence_get(i);
-    g_print("Lookup(%s) -> 0x%016llx\n", name, dirent->hash);
     if (dirent->hash != hash)
         return 0;
     if (g_strcmp0(name, dirent->name) != 0)
         return 0;
 
+    g_print("Lookup(%s) -> 0x%016llx\n", name, dirent->hash);
     return dirent->inum;
 }
 
@@ -96,13 +102,24 @@ gboolean bluesky_directory_insert(BlueSkyInode *dir, gchar *name, uint64_t inum)
     uint64_t hash = bluesky_directory_hash(name);
 
     BlueSkyDirent *d = g_new(BlueSkyDirent, 1);
-    d->name = name;
+    d->name = g_strdup(name);
     d->hash = hash;
     d->inum = inum;
 
     GSequenceIter *i = g_sequence_search(dir->dirents, d,
                                          bluesky_dirent_compare, NULL);
+
+    /* If a directory entry already exists, return failure.  The caller must
+     * delete the old entry and try again.  TODO: We'll fail on a hash
+     * collision; we should handle that case. */
+    if (!g_sequence_iter_is_end(g_sequence_iter_prev(i))) {
+        BlueSkyDirent *d2 = g_sequence_get(g_sequence_iter_prev(i));
+        if (d2->hash == hash)
+            return FALSE;
+    }
+
     g_sequence_insert_before(i, d);
+    dir->change_count++;
 
     return TRUE;
 }
diff --git a/inode.c b/inode.c
index ec90757..b9da798 100644 (file)
--- a/inode.c
+++ b/inode.c
@@ -24,6 +24,39 @@ int64_t bluesky_get_current_time()
     return t.tv_sec * 1000000 + t.tv_usec;
 }
 
+/* Unfortunately a glib hash table is only guaranteed to be able to store
+ * 32-bit keys if we use the key directly.  If we want 64-bit inode numbers,
+ * we'll have to allocate memory to store the 64-bit inumber, and use a pointer
+ * to it.  Rather than allocate the memory for the key, we'll just include a
+ * pointer to the 64-bit inum stored in the inode itself, so that we don't need
+ * to do any more memory management.  */
+static guint bluesky_fs_key_hash_func(gconstpointer key)
+{
+    uint64_t inum = *(const uint64_t *)key;
+    return (guint)inum;
+}
+
+static gboolean bluesky_fs_key_equal_func(gconstpointer a, gconstpointer b)
+{
+    uint64_t i1 = *(const uint64_t *)a;
+    uint64_t i2 = *(const uint64_t *)b;
+    return i1 == i2;
+}
+
+/* Filesystem-level operations.  A filesystem is like a directory tree that we
+ * are willing to export. */
+BlueSkyFS *bluesky_new_fs(gchar *name)
+{
+    BlueSkyFS *fs = g_new0(BlueSkyFS, 1);
+    fs->lock = g_mutex_new();
+    fs->name = g_strdup(name);
+    fs->inodes = g_hash_table_new(bluesky_fs_key_hash_func,
+                                  bluesky_fs_key_equal_func);
+    fs->next_inum = BLUESKY_ROOT_INUM + 1;
+
+    return fs;
+}
+
 /* Allocate a fresh inode number which has not been used before within a
  * filesystem. */
 uint64_t bluesky_fs_alloc_inode(BlueSkyFS *fs)
@@ -38,12 +71,48 @@ uint64_t bluesky_fs_alloc_inode(BlueSkyFS *fs)
     return inum;
 }
 
-BlueSkyInode *bluesky_new_inode(uint64_t inum)
+BlueSkyInode *bluesky_new_inode(uint64_t inum, BlueSkyFileType type)
 {
     BlueSkyInode *i = g_new0(BlueSkyInode, 1);
 
     i->lock = g_mutex_new();
+    i->type = type;
     i->inum = inum;
 
+    switch (type) {
+    case BLUESKY_REGULAR:
+        break;
+    case BLUESKY_DIRECTORY:
+        i->dirents = g_sequence_new(bluesky_dirent_destroy);
+    case BLUESKY_BLOCK:
+    case BLUESKY_CHARACTER:
+    case BLUESKY_SYMLINK:
+    case BLUESKY_SOCKET:
+    case BLUESKY_FIFO:
+        break;
+    }
+
     return i;
 }
+
+/* Retrieve an inode from the filesystem.  Eventually this will be a cache and
+ * so we might need to go fetch the inode from elsewhere; for now all
+ * filesystem state is stored here. */
+BlueSkyInode *bluesky_get_inode(BlueSkyFS *fs, uint64_t inum)
+{
+    BlueSkyInode *inode = NULL;
+
+    g_mutex_lock(fs->lock);
+    inode = (BlueSkyInode *)g_hash_table_lookup(fs->inodes, &inum);
+    g_mutex_unlock(fs->lock);
+
+    return inode;
+}
+
+/* Insert an inode into the filesystem inode cache. */
+void bluesky_insert_inode(BlueSkyFS *fs, BlueSkyInode *inode)
+{
+    g_mutex_lock(fs->lock);
+    g_hash_table_insert(fs->inodes, &inode->inum, inode);
+    g_mutex_unlock(fs->lock);
+}
diff --git a/main.c b/main.c
index 6ddc7b4..9c92356 100644 (file)
--- a/main.c
+++ b/main.c
@@ -21,9 +21,7 @@ int main(int argc, char *argv[])
 
     printf("BlueSkyFS starting...\n");
 
-    BlueSkyInode *root = bluesky_new_inode(1);
-    root->type = BLUESKY_DIRECTORY;
-    root->dirents = g_sequence_new(bluesky_dirent_destroy);
+    BlueSkyInode *root = bluesky_new_inode(1, BLUESKY_DIRECTORY);
 
     bluesky_directory_insert(root, "foo", 2);
     bluesky_directory_insert(root, "bar", 3);
@@ -34,6 +32,7 @@ int main(int argc, char *argv[])
     bluesky_directory_lookup(root, "foo");
     bluesky_directory_lookup(root, "bar");
     bluesky_directory_lookup(root, "baz");
+    bluesky_directory_lookup(root, "boo");
 
     return 0;
 }
index 87b2c04..59ee50b 100644 (file)
@@ -1,6 +1,6 @@
-PACKAGES=glib-2.0
+PACKAGES=glib-2.0 gthread-2.0
 DEBUG=-g
-CFLAGS=-O -Wall -D_FILE_OFFSET_BITS=64 $(DEBUG) \
+CFLAGS=-O -Wall -D_FILE_OFFSET_BITS=64 $(DEBUG) -I.. \
        $(shell pkg-config --cflags $(PACKAGES))
 LDFLAGS=$(DEBUG) $(shell pkg-config --libs $(PACKAGES))
 
@@ -8,7 +8,7 @@ SRCS=nfsd.c rpc.c mount.c nfs3.c mount_prot_xdr.c nfs3_prot_xdr.c
 OBJS=$(SRCS:.c=.o)
 
 nfsproxy : $(OBJS)
-       $(CC) $(LDFLAGS) -o $@ $^
+       $(CC) $(LDFLAGS) -o $@ $^ ../bluesky.a
 
 clean :
        rm -f $(OBJS) nfsproxy
index e4eb3a1..8b2ba7b 100644 (file)
@@ -19,8 +19,8 @@ mountproc3_null_3_svc(void *argp, struct svc_req *rqstp)
 mountres3 *
 mountproc3_mnt_3_svc(dirpath *argp, struct svc_req *rqstp)
 {
-    static char fhbytes[] = {0, 0, 0, 1};
-    static fhandle3 fh = {4, fhbytes};
+    static char fhbytes[] = {0, 0, 0, 0, 0, 0, 0, 1};
+    static fhandle3 fh = {8, fhbytes};
     static mountres3 result;
     static int auth_flavors = AUTH_UNIX;
 
index cbf5650..25552a7 100644 (file)
@@ -5,29 +5,46 @@
  */
 
 #include "nfs3_prot.h"
+#include "bluesky.h"
+
+extern BlueSkyFS *fs;
 
 static int null_int;
 static void *null_result = (void *)&null_int;
 
-void encode_fattr3(struct fattr3 *result, uint64_t inum)
+/* Look up a BlueSkyInode given an NFS filehandle.  Returns NULL if the
+ * filehandle is invalid. */
+BlueSkyInode *lookup_fh(nfs_fh3 *fh)
 {
-    result->type = NF3DIR;
-    result->mode = 0755;
-    result->nlink = 1;
-    result->uid = 0;
-    result->gid = 0;
-    result->size = 0;
+    BlueSkyInode *inode = NULL;
+    if (fh->data.data_len == 8) {
+        uint64_t inum = GUINT64_FROM_BE(*(uint64_t *)(fh->data.data_val));
+        inode = bluesky_get_inode(fs, inum);
+    }
+    return inode;
+}
+
+/* Copy inode attributes into NFS response.  The BlueSkyInode should be locked
+ * by the caller. */
+void encode_fattr3(struct fattr3 *result, BlueSkyInode *inode)
+{
+    result->type = inode->type;
+    result->mode = inode->mode;
+    result->nlink = inode->nlink;
+    result->uid = inode->uid;
+    result->gid = inode->gid;
+    result->size = inode->size;
     result->used = 0;
     result->rdev.major = 0;
     result->rdev.minor = 0;
     result->fsid = 0;
-    result->fileid = inum;
-    result->atime.seconds = 0;
-    result->atime.nseconds = 0;
-    result->mtime.seconds = 0;
-    result->mtime.nseconds = 0;
-    result->ctime.seconds = 0;
-    result->ctime.nseconds = 0;
+    result->fileid = inode->inum;
+    result->atime.seconds = inode->atime / 1000000;
+    result->atime.nseconds = (inode->atime % 1000000) * 1000;
+    result->mtime.seconds = inode->mtime / 1000000;
+    result->mtime.nseconds = (inode->mtime % 1000000) * 1000;
+    result->ctime.seconds = inode->ctime / 1000000;
+    result->ctime.nseconds = (inode->ctime % 1000000) * 1000;
 }
 
 void *
@@ -41,8 +58,13 @@ nfsproc3_getattr_3_svc(nfs_fh3 *argp, struct svc_req *rqstp)
 {
     static getattr3res result;
 
-    result.status = NFS3_OK;
-    encode_fattr3(&result.getattr3res_u.attributes, 1);
+    BlueSkyInode *inode = lookup_fh(argp);
+    if (inode != NULL) {
+        result.status = NFS3_OK;
+        encode_fattr3(&result.getattr3res_u.attributes, inode);
+    } else {
+        result.status = NFS3ERR_STALE;
+    }
 
     return &result;
 }
@@ -222,9 +244,10 @@ nfsproc3_fsinfo_3_svc(nfs_fh3 *argp, struct svc_req *rqstp)
 {
     static fsinfo3res result;
 
+    BlueSkyInode *inode = bluesky_get_inode(fs, 1);
     result.status = NFS3_OK;
     result.fsinfo3res_u.resok.obj_attributes.present = TRUE;
-    encode_fattr3(&result.fsinfo3res_u.resok.obj_attributes.post_op_attr_u.attributes, 1);
+    encode_fattr3(&result.fsinfo3res_u.resok.obj_attributes.post_op_attr_u.attributes, inode);
     result.fsinfo3res_u.resok.rtmax = 32768;
     result.fsinfo3res_u.resok.rtpref = 32768;
     result.fsinfo3res_u.resok.rtmult = 4096;
@@ -246,9 +269,10 @@ nfsproc3_pathconf_3_svc(nfs_fh3 *argp, struct svc_req *rqstp)
 {
     static pathconf3res result;
 
+    BlueSkyInode *inode = bluesky_get_inode(fs, 1);
     result.status = NFS3_OK;
     result.pathconf3res_u.resok.obj_attributes.present = TRUE;
-    encode_fattr3(&result.pathconf3res_u.resok.obj_attributes.post_op_attr_u.attributes, 1);
+    encode_fattr3(&result.pathconf3res_u.resok.obj_attributes.post_op_attr_u.attributes, inode);
     result.pathconf3res_u.resok.linkmax = 0xffffffff;
     result.pathconf3res_u.resok.name_max = 255;
     result.pathconf3res_u.resok.no_trunc = TRUE;
index 7a0338d..03b39fb 100644 (file)
 #include <memory.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
+#include <glib.h>
+
+#include "bluesky.h"
 
 void register_rpc();
 
+BlueSkyFS *fs;
+
 int main(int argc, char *argv[])
 {
+    g_thread_init(NULL);
     register_rpc();
 
+    BlueSkyInode *root;
+    root = bluesky_new_inode(BLUESKY_ROOT_INUM, BLUESKY_DIRECTORY);
+    root->nlink = 1;
+    root->mode = 0755;
+    bluesky_insert_inode(fs, root);
+
     svc_run ();
     fprintf (stderr, "%s", "svc_run returned");
     exit (1);