ext2_dealloc_inode(), clarifies dealloc vs delete
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 8 Sep 2010 01:37:24 +0000 (18:37 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:53 +0000 (17:35 -0700)
Documentation/vfs.txt
kern/include/vfs.h
kern/src/ext2fs.c
kern/src/kfs.c
kern/src/vfs.c

index e2f1b8a..d6507b0 100644 (file)
@@ -289,3 +289,41 @@ the in-memory objects.  A directory cannot be removed if nlinks > 1.  If it is
 1, then you can rmdir it, which will set its nlinks to 0.  Then its inode's
 storage space will get freed when it is deleted, like any other inode.  In
 theory.
+
+Inodes: drop? delete? dealloc?
+--------------------------
+Inodes exist both in memory and on disk, but in different manners.  When a file
+(F_WHATEVER, could be DIR) exists in an FS, it'll have an inode on disk.  When
+it is time to delete that file, we call _delete_inode().  When we want to free
+the memory associated with an in-memory (VFS) inode, we call _dealloc_inode().
+
+What about drop_inode?  For now, we don't use it.  We have inode_release() in
+the VFS.  If we need an FS specific one (like for ext2), or have FS-specific
+work that needs to be done in inode_release(), we'll use it later.
+
+Either way, inode_release() is called when we no longer use the in-memory inode.
+If there are no hard links, it will delete the inode.  Either way, it will just
+free the in-memory inode (after deleting the disc version).
+
+Example: I want to unlink (rm) a file.  There are two cases: the file is already
+open (with a dentry and the inode in memory) or the file is not.  Both cases are
+handled the same way!  In either case, we eventually call do_lookup on the item
+in question, getting both a dentry and its inode read in.  (We read it in for a
+couple reasons: convenient to check the type, and we need to manipulate the
+nlink).  If a process has the file open, or even if it is sitting in the cache,
+we will get the same inode (from the inode cache, might not be implemented yet).
+When we decref the dentry and it is done, it will decref the inode.  This
+dentry's final decref will be deferred until any open files are closed.  Note,
+this requires a working dentry/inode-cache - otherwise we'll have multiple
+copies of the same FS/disk-inode (and possibly dentry).  Anyway, when this is
+done, the release function will delete the inode, then dealloc it.
+
+Another example:  We simply close a file.  When that happens, we decref the
+dentry, which decrefs the inode.  It may remain cached for a bit - not a big
+deal.  When it is finally removed, nlinks is positive, so the inode's in memory
+copy is written back (if it was dirty) and the structure is deallocated.
+
+Side notes: dentry cached inodes should be removed after their lookup in unlink.
+Also, since multiple dentries point to the same inode, it's not enough to just
+cache dentries - we need to be able to find inodes too so that we get the one
+inode regardless of which dentry we use (which may be uncached).
index 9a034b7..d770c0e 100644 (file)
@@ -185,6 +185,9 @@ struct super_operations {
 /* Sets the type of file, IAW the bits in ros/fs.h */
 #define SET_FTYPE(mode, type) ((mode) = ((mode) & ~__S_IFMT) | (type))
 
+/* Will need a bunch of states/flags for an inode.  TBD */
+#define I_STATE_DIRTY                  0x001
+
 /* Inode: represents a specific file */
 struct inode {
        SLIST_ENTRY(inode)                      i_hash;                 /* inclusion in a hash table */
index 29e0bd4..9c157c3 100644 (file)
@@ -2,8 +2,8 @@
  * Barret Rhoden <brho@cs.berkeley.edu>
  * See LICENSE for details.
  *
- * For now, just a lot of debugging / bootstrapping functions for ext2.
- */
+ * Ext2, VFS required functions, internal functions, life, the universe, and
+ * everything! */
 
 #include <vfs.h>
 #include <ext2fs.h>
@@ -367,22 +367,12 @@ struct inode *ext2_alloc_inode(struct super_block *sb)
        return inode;
 }
 
-/* deallocs and cleans up after an inode. */
+/* FS-specific clean up when an inode is dealloced.  this is just cleaning up
+ * the in-memory version, and only the FS-specific parts.  whether or not the
+ * inode is still on disc is irrelevant. */
 void ext2_dealloc_inode(struct inode *inode)
 {
-       static bool ran_once = FALSE;
-       if (!ran_once) {
-               ran_once = TRUE;
-               warn("Implement %s(), you're leaking memory!\n", __FUNCTION__);
-       }
-/* too verbose, but it's a TODO... */
-//I_AM_HERE;
-       #if 0
-       /* If we're a symlink, give up our storage for the symname */
-       if (S_ISLNK(inode->i_mode))
-               kfree(((struct ext2_i_info*)inode->i_fs_info)->filestart);
        kmem_cache_free(ext2_i_kcache, inode->i_fs_info);
-       #endif
 }
 
 /* reads the inode data on disk specified by inode->i_ino into the inode.
@@ -469,21 +459,17 @@ void ext2_put_inode(struct inode *inode)
 I_AM_HERE;
 }
 
-/* called when an inode is about to be destroyed.  the generic version ought to
- * remove every reference to the inode from the VFS, and if the inode isn't in
- * any directory, calls delete_inode */
+/* Unused for now, will get rid of this if inode_release is sufficient */
 void ext2_drop_inode(struct inode *inode)
-{ // TODO: should call a generic one instead.  or at least do something...
-       // remove from lists
+{
 I_AM_HERE;
 }
 
-/* delete the inode from disk (all data) and deallocs the in memory inode */
+/* delete the inode from disk (all data) */
 void ext2_delete_inode(struct inode *inode)
 {
 I_AM_HERE;
        // would remove from "disk" here
-       ext2_dealloc_inode(inode);
        /* TODO: give up our i_ino */
 }
 
index 61685e0..09570a6 100644 (file)
@@ -165,7 +165,9 @@ struct inode *kfs_alloc_inode(struct super_block *sb)
        return inode;
 }
 
-/* deallocs and cleans up after an inode. */
+/* FS-specific clean up when an inode is dealloced.  this is just cleaning up
+ * the in-memory version, and only the FS-specific parts.  whether or not the
+ * inode is still on disc is irrelevant. */
 void kfs_dealloc_inode(struct inode *inode)
 {
        /* If we're a symlink, give up our storage for the symname */
@@ -230,11 +232,10 @@ void kfs_drop_inode(struct inode *inode)
        // remove from lists
 }
 
-/* delete the inode from disk (all data) and deallocs the in memory inode */
+/* delete the inode from disk (all data) */
 void kfs_delete_inode(struct inode *inode)
 {
        // would remove from "disk" here
-       kfs_dealloc_inode(inode);
        /* TODO: give up our i_ino */
 }
 
index 2600914..119ae65 100644 (file)
@@ -821,12 +821,15 @@ void inode_release(struct kref *kref)
 {
        struct inode *inode = container_of(kref, struct inode, i_kref);
        TAILQ_REMOVE(&inode->i_sb->s_inodes, inode, i_sb_list);
-       /* If we still have links, just dealloc the in-memory inode.  if we have no
-        * links, we need to delete it too (which calls destroy). */
-       if (inode->i_nlink)
-               inode->i_sb->s_op->dealloc_inode(inode);
-       else
+       /* Might need to write back or delete the file/inode */
+       if (inode->i_nlink) {
+               if (inode->i_state & I_STATE_DIRTY)
+                       inode->i_sb->s_op->write_inode(inode, TRUE);
+       } else {
                inode->i_sb->s_op->delete_inode(inode);
+       }
+       /* Either way, we dealloc the in-memory version */
+       inode->i_sb->s_op->dealloc_inode(inode);        /* FS-specific clean-up */
        kref_put(&inode->i_sb->s_kref);
        assert(inode->i_mapping == &inode->i_pm);
        kmem_cache_free(inode_kcache, inode);
@@ -1225,6 +1228,7 @@ int do_unlink(char *path)
                set_errno(-error);
                goto out_dentry;
        }
+       /* TODO: rip dentry from the inode cache */
        kref_put(&dentry->d_parent->d_kref);
        dentry->d_parent = 0;           /* so we don't double-decref it later */
        dentry->d_inode->i_nlink--;     /* TODO: race here, esp with a decref */