kfs_lookup() and parsing directories
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 9 Jun 2010 00:25:20 +0000 (17:25 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:48 +0000 (17:35 -0700)
KFS now builds a full tree from a CPIO archive.  No support for symlinks
or anything like that yet.

Documentation/vfs.txt
kern/include/vfs.h
kern/src/kfs.c
kern/src/vfs.c

index f977671..abb14c8 100644 (file)
@@ -74,7 +74,7 @@ just means we need to think about what we really want from a refcnt, and whether
 or not we want the kref / process style refcnting.
 
 Mounting:
-
+-------------------------------------------
 When you mount, you need to read in the super block and connect the relevant
 data structures together.  The SB is connected to the vfsmount, which is
 connected to the dentry of the mount point and the dentry of the root of the FS.
@@ -89,7 +89,7 @@ up to the real root are all in memory too.  Having a mount point is like having
 a process working in that directory - the chain back up is pinned.
 
 d_subdirs:
-
+-------------------------------------------
 Tracking the links between objects can be tricky.  One pain is d_subdirs. Linux
 only tracks subdirectories.  We also do this.  I think the reason they do it is
 since you should be using the dcache to cache lookups, and not scan the linked
@@ -97,3 +97,12 @@ list of children of a dentry for a specific file.  Though it is handy to know
 all of your *directory* children.  In KFS, we also track all children in a list.
 This is to make our lookups work - instead of having an actual directory file
 with name->ino mappings.
+
+KFS and metadata pinning:
+-------------------------------------------
+KFS pins all metadata ("all paths pinned").  This means that from the root mnt
+down to the lowest inode, all dentries and corresponding inodes are pinned in
+memory from creation time.   Yeah, this means we have chunks of metadata for
+files we aren't using sitting around in RAM.  We also have the *files* sitting
+around in RAM too.  Not that concerned, for now.  Plus, I don't want to reparse
+the CPIO backing store to figure out inode fields, directory names, etc.
index 2db3728..90c62de 100644 (file)
@@ -88,7 +88,7 @@ struct nameidata {
        struct vfsmount                         *mnt;                   /* its mount pt */
        struct qstr                                     last;                   /* last component in search */
        int                                                     flags;                  /* lookup flags */
-       int                                                     last_type;              /* type fo last component */
+       int                                                     last_type;              /* type of last component */
        unsigned int                            depth;                  /* search's symlink depth */
        char                                            *saved_names[MAX_SYMLINK_DEPTH];
        int                                                     intent;                 /* access type for the file */
index 6e8a983..cff5c2b 100644 (file)
@@ -290,16 +290,52 @@ int kfs_create(struct inode *dir, struct dentry *dentry, int mode,
 }
 
 /* Searches the directory for the filename in the dentry, filling in the dentry
- * with the FS specific info of this file */
+ * with the FS specific info of this file.  If it succeeds, it will pass back
+ * the *dentry you should use.  If this fails, it will return 0 and will take
+ * the ref to the dentry for you.  Either way, you shouldn't use the ref you
+ * passed in anymore.
+ *
+ * Callers, make sure you alloc and fill out the name parts of the dentry, and
+ * an initialized nameidata.
+ *
+ * Doesn't yet handle symlinks, . or .., so don't fuck it up.  Some of the other
+ * ugliness is because KFS is exclusively using dentries to track subdirs,
+ * instead of putting it all in the inode/dir file.
+ *
+ * Because of the way KFS currently works, if there is ever a dentry, it's
+ * already in memory, along with its inode (all path's pinned).  So we just find
+ * it and return it. */
 struct dentry *kfs_lookup(struct inode *dir, struct dentry *dentry,
                           struct nameidata *nd)
 {
-       // TODO: does this mean the inode too?
-       // what the hell are we returning?  the passed in dentry?  an error code?
-       // this will have to read the directory, then find the ino, then creates a
-       // dentry for it
-       //
-       // linux now has a nameidata for this
+       struct kfs_i_info *k_i_info = (struct kfs_i_info*)dir->i_fs_info;
+       struct dentry *dir_dent = TAILQ_FIRST(&dir->i_dentry);
+       struct dentry *d_i;
+
+       assert(dir_dent && dir_dent == TAILQ_LAST(&dir->i_dentry, dentry_tailq));
+       assert(dir->i_flags & FS_I_DIR);
+
+       TAILQ_FOREACH(d_i, &dir_dent->d_subdirs, d_subdirs_link) {
+               if (!strcmp(d_i->d_name.name, dentry->d_name.name)) {
+                       /* since this dentry is already in memory (that's how KFS works), we
+                        * can free the one that came in and return the real one */
+                       kmem_cache_free(dentry_kcache, dentry);
+                       return d_i;
+               }
+       }
+       TAILQ_FOREACH(d_i, &k_i_info->children, d_subdirs_link) {
+               if (!strcmp(d_i->d_name.name, dentry->d_name.name)) {
+                       /* since this dentry is already in memory (that's how KFS works), we
+                        * can free the one that came in and return the real one */
+                       kmem_cache_free(dentry_kcache, dentry);
+                       return d_i;
+               }
+       }
+       /* no match, consider caching the negative result, freeing the
+        * dentry, etc */
+       printk("Not Found %s!!\n", dentry->d_name.name);
+       /* TODO: Cache, negatively... */
+       //dcache_put(dentry);                   /* TODO: should set a d_flag too */
        return 0;
 }
 
@@ -429,7 +465,10 @@ int kfs_d_delete(struct dentry *dentry)
 
 /* Called when it's about to be slab-freed */
 int kfs_d_release(struct dentry *dentry)
-{ // default, nothin
+{
+       /* TODO: check the boundaries on this. */
+       if (dentry->d_name.len > DNAME_INLINE_LEN)
+               kfree((void*)dentry->d_name.name);
        return -1;
 }
 
@@ -700,14 +739,18 @@ void kfs_cat(int kfs_inode)
                cputchar(*ptr);
 }
 
-/* Need to pass path separately, since we'll recurse on it */
+/* Need to pass path separately, since we'll recurse on it.  TODO: this recurses,
+ * and takes up a lot of stack space (~270 bytes).  Core 0's KSTACK is 8 pages,
+ * which can handle about 120 levels deep...  Other cores are not so fortunate.
+ * Can rework this if it becomes an issue. */
 static int __add_kfs_entry(struct dentry *parent, char *path,
                            struct cpio_bin_hdr *c_bhdr)
 {
        char *first_slash = strchr(path, '/');  
        char dir[MAX_FILENAME_SZ + 1];  /* room for the \0 */
        size_t dirname_sz;                              /* not counting the \0 */
-       struct dentry *dentry;
+       struct dentry *dentry = 0;
+       struct nameidata nd = {0};
        struct inode *inode;
 
        if (first_slash) {
@@ -718,16 +761,27 @@ static int __add_kfs_entry(struct dentry *parent, char *path,
                assert(dirname_sz <= MAX_FILENAME_SZ);
                strncpy(dir, path, dirname_sz);
                dir[dirname_sz] = '\0';
-               printk("Finding DIR %s in dentry %s (start: %p, size %d)\n", dir,
+               printd("Finding DIR %s in dentry %s (start: %p, size %d)\n", dir,
                       parent->d_name.name, c_bhdr->c_filestart, c_bhdr->c_filesize);
-               // send to the real dentry
-               __add_kfs_entry(parent, first_slash + 1, c_bhdr);
-
+               /* Need to create a dentry for the lookup, and fill in the basic nd */
+               dentry = get_dentry(parent->d_sb, parent, dir);
+               nd.dentry = dentry;
+               nd.mnt = dentry->d_sb->s_mount;
+               //nd.flags = 0;                 /* TODO: once we have lookup flags */
+               //nd.last_type = 0;             /* TODO: should be a DIR */
+               //nd.intent = 0;                /* TODO: RW, prob irrelevant*/
+               /* TODO: use a VFS lookup instead, to use the dcache, thought its not a
+                * big deal since KFS currently pins all metadata. */
+               dentry = kfs_lookup(parent->d_inode, dentry, &nd);
+               if (!dentry) {
+                       printk("Missing dir in CPIO archive or something, aborting.\n");
+                       return -1;
+               }
+               return __add_kfs_entry(dentry, first_slash + 1, c_bhdr);
        } else {
                /* no directories left in the path.  add the 'file' to the dentry */
-               printk("Adding file/dir %s to dentry %s (start: %p, size %d)\n", path,
+               printd("Adding file/dir %s to dentry %s (start: %p, size %d)\n", path,
                       parent->d_name.name, c_bhdr->c_filestart, c_bhdr->c_filesize);
-
                /* Init the dentry for this path */
                dentry = get_dentry(parent->d_sb, parent, path);
                dentry->d_op = &kfs_d_op;
@@ -813,7 +867,7 @@ void parse_cpio_entries(struct super_block *sb, void *cpio_b)
                c_bhdr->c_dev_min = cpio_strntol(buf, c_hdr->c_dev_min, 8);
                c_bhdr->c_rdev_maj = cpio_strntol(buf, c_hdr->c_rdev_maj, 8);
                c_bhdr->c_rdev_min = cpio_strntol(buf, c_hdr->c_rdev_min, 8);
-               printk("File: %s: %d Bytes\n", c_bhdr->c_filename, c_bhdr->c_filesize);
+               printd("File: %s: %d Bytes\n", c_bhdr->c_filename, c_bhdr->c_filesize);
                offset += namesize;
                /* header + name will be padded out to 4-byte alignment */
                offset = ROUNDUP(offset, 4);
index 7bb5ab0..adc3e2d 100644 (file)
@@ -186,15 +186,18 @@ void init_sb(struct super_block *sb, struct vfsmount *vmnt,
        dcache_put(d_root); // TODO: should set a d_flag too
 }
 
-/* Helper to alloc and initialize a generic dentry.  Note that this may store
- * the char *name inside the dentry (if it was longer than the inline length).
- * That might turn out to suck.  */
+/* Helper to alloc and initialize a generic dentry.
+ *
+ * If the name is longer than the inline name, it will kmalloc a buffer, so
+ * don't worry about the storage for *name after calling this. */
 struct dentry *get_dentry(struct super_block *sb, struct dentry *parent,
                           char *name)
 {
        assert(name);
-       size_t name_len = strnlen(name, MAX_FILENAME_SZ);
+       size_t name_len = strnlen(name, MAX_FILENAME_SZ);       /* not including \0! */
        struct dentry *dentry = kmem_cache_alloc(dentry_kcache, 0);
+       char *l_name = 0;
+
        //memset(dentry, 0, sizeof(struct dentry));
        atomic_set(&dentry->d_refcnt, 1);       /* this ref is returned */
        spinlock_init(&dentry->d_lock);
@@ -209,11 +212,16 @@ struct dentry *get_dentry(struct super_block *sb, struct dentry *parent,
        dentry->d_flags = 0;                            /* related to its dcache state */
        dentry->d_fs_info = 0;
        SLIST_INIT(&dentry->d_bucket);
-       if (name_len <= DNAME_INLINE_LEN) {
+       if (name_len < DNAME_INLINE_LEN) {
                strncpy(dentry->d_iname, name, name_len);
+               dentry->d_iname[name_len] = '\0';
                qstr_builder(dentry, 0);
        } else {
-               qstr_builder(dentry, name);             /* storing the incoming *name */
+               l_name = kmalloc(name_len + 1, 0);
+               assert(l_name);
+               strncpy(l_name, name, name_len);
+               l_name[name_len] = '\0';
+               qstr_builder(dentry, l_name);
        }
        return dentry;
 }