gfs2: lookup local statfs inodes prior to journal recovery
[linux-2.6-microblaze.git] / fs / gfs2 / super.c
index 9f4d9e7..b285192 100644 (file)
 #include "xattr.h"
 #include "lops.h"
 
+enum dinode_demise {
+       SHOULD_DELETE_DINODE,
+       SHOULD_NOT_DELETE_DINODE,
+       SHOULD_DEFER_EVICTION,
+};
+
 /**
  * gfs2_jindex_free - Clear all the journal index information
  * @sdp: The GFS2 superblock
@@ -224,7 +230,7 @@ void gfs2_statfs_change_in(struct gfs2_statfs_change_host *sc, const void *buf)
        sc->sc_dinodes = be64_to_cpu(str->sc_dinodes);
 }
 
-static void gfs2_statfs_change_out(const struct gfs2_statfs_change_host *sc, void *buf)
+void gfs2_statfs_change_out(const struct gfs2_statfs_change_host *sc, void *buf)
 {
        struct gfs2_statfs_change *str = buf;
 
@@ -702,6 +708,8 @@ restart:
                if (error)
                        gfs2_io_error(sdp);
        }
+       WARN_ON(gfs2_withdrawing(sdp));
+
        /*  At this point, we're through modifying the disk  */
 
        /*  Release stuff  */
@@ -721,7 +729,7 @@ restart:
                        gfs2_glock_dq_uninit(&sdp->sd_jinode_gh);
                gfs2_glock_dq_uninit(&sdp->sd_sc_gh);
                gfs2_glock_dq_uninit(&sdp->sd_qc_gh);
-               iput(sdp->sd_sc_inode);
+               free_local_statfs_inodes(sdp);
                iput(sdp->sd_qc_inode);
        }
 
@@ -736,6 +744,7 @@ restart:
 
        /*  At this point, we're through participating in the lockspace  */
        gfs2_sys_fs_del(sdp);
+       free_sbd(sdp);
 }
 
 /**
@@ -1309,109 +1318,98 @@ static bool gfs2_upgrade_iopen_glock(struct inode *inode)
 }
 
 /**
- * gfs2_evict_inode - Remove an inode from cache
+ * evict_should_delete - determine whether the inode is eligible for deletion
  * @inode: The inode to evict
  *
- * There are three cases to consider:
- * 1. i_nlink == 0, we are final opener (and must deallocate)
- * 2. i_nlink == 0, we are not the final opener (and cannot deallocate)
- * 3. i_nlink > 0
- *
- * If the fs is read only, then we have to treat all cases as per #3
- * since we are unable to do any deallocation. The inode will be
- * deallocated by the next read/write node to attempt an allocation
- * in the same resource group
+ * This function determines whether the evicted inode is eligible to be deleted
+ * and locks the inode glock.
  *
- * We have to (at the moment) hold the inodes main lock to cover
- * the gap between unlocking the shared lock on the iopen lock and
- * taking the exclusive lock. I'd rather do a shared -> exclusive
- * conversion on the iopen lock, but we can change that later. This
- * is safe, just less efficient.
+ * Returns: the fate of the dinode
  */
-
-static void gfs2_evict_inode(struct inode *inode)
+static enum dinode_demise evict_should_delete(struct inode *inode,
+                                             struct gfs2_holder *gh)
 {
+       struct gfs2_inode *ip = GFS2_I(inode);
        struct super_block *sb = inode->i_sb;
        struct gfs2_sbd *sdp = sb->s_fs_info;
-       struct gfs2_inode *ip = GFS2_I(inode);
-       struct gfs2_holder gh;
-       struct address_space *metamapping;
-       int error;
-
-       if (test_bit(GIF_FREE_VFS_INODE, &ip->i_flags)) {
-               clear_inode(inode);
-               return;
-       }
-
-       if (inode->i_nlink || sb_rdonly(sb))
-               goto out;
+       int ret;
 
        if (test_bit(GIF_ALLOC_FAILED, &ip->i_flags)) {
                BUG_ON(!gfs2_glock_is_locked_by_me(ip->i_gl));
-               gfs2_holder_mark_uninitialized(&gh);
-               goto out_delete;
+               goto should_delete;
        }
 
        if (test_bit(GIF_DEFERRED_DELETE, &ip->i_flags))
-               goto out;
+               return SHOULD_DEFER_EVICTION;
 
        /* Deletes should never happen under memory pressure anymore.  */
        if (WARN_ON_ONCE(current->flags & PF_MEMALLOC))
-               goto out;
+               return SHOULD_DEFER_EVICTION;
 
        /* Must not read inode block until block type has been verified */
-       error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_SKIP, &gh);
-       if (unlikely(error)) {
+       ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_SKIP, gh);
+       if (unlikely(ret)) {
                glock_clear_object(ip->i_iopen_gh.gh_gl, ip);
                ip->i_iopen_gh.gh_flags |= GL_NOCACHE;
                gfs2_glock_dq_uninit(&ip->i_iopen_gh);
-               goto out;
+               return SHOULD_DEFER_EVICTION;
        }
 
        if (gfs2_inode_already_deleted(ip->i_gl, ip->i_no_formal_ino))
-               goto out_truncate;
-       error = gfs2_check_blk_type(sdp, ip->i_no_addr, GFS2_BLKST_UNLINKED);
-       if (error)
-               goto out_truncate;
+               return SHOULD_NOT_DELETE_DINODE;
+       ret = gfs2_check_blk_type(sdp, ip->i_no_addr, GFS2_BLKST_UNLINKED);
+       if (ret)
+               return SHOULD_NOT_DELETE_DINODE;
 
        if (test_bit(GIF_INVALID, &ip->i_flags)) {
-               error = gfs2_inode_refresh(ip);
-               if (error)
-                       goto out_truncate;
+               ret = gfs2_inode_refresh(ip);
+               if (ret)
+                       return SHOULD_NOT_DELETE_DINODE;
        }
 
        /*
         * The inode may have been recreated in the meantime.
         */
        if (inode->i_nlink)
-               goto out_truncate;
+               return SHOULD_NOT_DELETE_DINODE;
 
-out_delete:
+should_delete:
        if (gfs2_holder_initialized(&ip->i_iopen_gh) &&
            test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags)) {
                if (!gfs2_upgrade_iopen_glock(inode)) {
                        gfs2_holder_uninit(&ip->i_iopen_gh);
-                       goto out_truncate;
+                       return SHOULD_NOT_DELETE_DINODE;
                }
        }
+       return SHOULD_DELETE_DINODE;
+}
+
+/**
+ * evict_unlinked_inode - delete the pieces of an unlinked evicted inode
+ * @inode: The inode to evict
+ */
+static int evict_unlinked_inode(struct inode *inode)
+{
+       struct gfs2_inode *ip = GFS2_I(inode);
+       int ret;
 
        if (S_ISDIR(inode->i_mode) &&
            (ip->i_diskflags & GFS2_DIF_EXHASH)) {
-               error = gfs2_dir_exhash_dealloc(ip);
-               if (error)
-                       goto out_unlock;
+               ret = gfs2_dir_exhash_dealloc(ip);
+               if (ret)
+                       goto out;
        }
 
        if (ip->i_eattr) {
-               error = gfs2_ea_dealloc(ip);
-               if (error)
-                       goto out_unlock;
+               ret = gfs2_ea_dealloc(ip);
+               if (ret)
+                       goto out;
        }
 
        if (!gfs2_is_stuffed(ip)) {
-               error = gfs2_file_dealloc(ip);
-               if (error)
-                       goto out_unlock;
+               ret = gfs2_file_dealloc(ip);
+               if (ret)
+                       goto out;
        }
 
        /* We're about to clear the bitmap for the dinode, but as soon as we
@@ -1419,11 +1417,24 @@ out_delete:
           location and try to set gl_object again. We clear gl_object here so
           that subsequent inode creates don't see an old gl_object. */
        glock_clear_object(ip->i_gl, ip);
-       error = gfs2_dinode_dealloc(ip);
+       ret = gfs2_dinode_dealloc(ip);
        gfs2_inode_remember_delete(ip->i_gl, ip->i_no_formal_ino);
-       goto out_unlock;
+out:
+       return ret;
+}
+
+/*
+ * evict_linked_inode - evict an inode whose dinode has not been unlinked
+ * @inode: The inode to evict
+ */
+static int evict_linked_inode(struct inode *inode)
+{
+       struct super_block *sb = inode->i_sb;
+       struct gfs2_sbd *sdp = sb->s_fs_info;
+       struct gfs2_inode *ip = GFS2_I(inode);
+       struct address_space *metamapping;
+       int ret;
 
-out_truncate:
        gfs2_log_flush(sdp, ip->i_gl, GFS2_LOG_HEAD_FLUSH_NORMAL |
                       GFS2_LFC_EVICT_INODE);
        metamapping = gfs2_glock2aspace(ip->i_gl);
@@ -1434,15 +1445,63 @@ out_truncate:
        write_inode_now(inode, 1);
        gfs2_ail_flush(ip->i_gl, 0);
 
-       error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks);
-       if (error)
-               goto out_unlock;
+       ret = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks);
+       if (ret)
+               return ret;
+
        /* Needs to be done before glock release & also in a transaction */
        truncate_inode_pages(&inode->i_data, 0);
        truncate_inode_pages(metamapping, 0);
        gfs2_trans_end(sdp);
+       return 0;
+}
+
+/**
+ * gfs2_evict_inode - Remove an inode from cache
+ * @inode: The inode to evict
+ *
+ * There are three cases to consider:
+ * 1. i_nlink == 0, we are final opener (and must deallocate)
+ * 2. i_nlink == 0, we are not the final opener (and cannot deallocate)
+ * 3. i_nlink > 0
+ *
+ * If the fs is read only, then we have to treat all cases as per #3
+ * since we are unable to do any deallocation. The inode will be
+ * deallocated by the next read/write node to attempt an allocation
+ * in the same resource group
+ *
+ * We have to (at the moment) hold the inodes main lock to cover
+ * the gap between unlocking the shared lock on the iopen lock and
+ * taking the exclusive lock. I'd rather do a shared -> exclusive
+ * conversion on the iopen lock, but we can change that later. This
+ * is safe, just less efficient.
+ */
+
+static void gfs2_evict_inode(struct inode *inode)
+{
+       struct super_block *sb = inode->i_sb;
+       struct gfs2_sbd *sdp = sb->s_fs_info;
+       struct gfs2_inode *ip = GFS2_I(inode);
+       struct gfs2_holder gh;
+       int ret;
+
+       if (test_bit(GIF_FREE_VFS_INODE, &ip->i_flags)) {
+               clear_inode(inode);
+               return;
+       }
+
+       if (inode->i_nlink || sb_rdonly(sb))
+               goto out;
+
+       gfs2_holder_mark_uninitialized(&gh);
+       ret = evict_should_delete(inode, &gh);
+       if (ret == SHOULD_DEFER_EVICTION)
+               goto out;
+       if (ret == SHOULD_DELETE_DINODE)
+               ret = evict_unlinked_inode(inode);
+       else
+               ret = evict_linked_inode(inode);
 
-out_unlock:
        if (gfs2_rs_active(&ip->i_res))
                gfs2_rs_deltree(&ip->i_res);
 
@@ -1450,8 +1509,8 @@ out_unlock:
                glock_clear_object(ip->i_gl, ip);
                gfs2_glock_dq_uninit(&gh);
        }
-       if (error && error != GLR_TRYFAILED && error != -EROFS)
-               fs_warn(sdp, "gfs2_evict_inode: %d\n", error);
+       if (ret && ret != GLR_TRYFAILED && ret != -EROFS)
+               fs_warn(sdp, "gfs2_evict_inode: %d\n", ret);
 out:
        truncate_inode_pages_final(&inode->i_data);
        if (ip->i_qadata)
@@ -1502,6 +1561,35 @@ static void gfs2_free_inode(struct inode *inode)
        kmem_cache_free(gfs2_inode_cachep, GFS2_I(inode));
 }
 
+extern void free_local_statfs_inodes(struct gfs2_sbd *sdp)
+{
+       struct local_statfs_inode *lsi, *safe;
+
+       /* Run through the statfs inodes list to iput and free memory */
+       list_for_each_entry_safe(lsi, safe, &sdp->sd_sc_inodes_list, si_list) {
+               if (lsi->si_jid == sdp->sd_jdesc->jd_jid)
+                       sdp->sd_sc_inode = NULL; /* belongs to this node */
+               if (lsi->si_sc_inode)
+                       iput(lsi->si_sc_inode);
+               list_del(&lsi->si_list);
+               kfree(lsi);
+       }
+}
+
+extern struct inode *find_local_statfs_inode(struct gfs2_sbd *sdp,
+                                            unsigned int index)
+{
+       struct local_statfs_inode *lsi;
+
+       /* Return the local (per node) statfs inode in the
+        * sdp->sd_sc_inodes_list corresponding to the 'index'. */
+       list_for_each_entry(lsi, &sdp->sd_sc_inodes_list, si_list) {
+               if (lsi->si_jid == index)
+                       return lsi->si_sc_inode;
+       }
+       return NULL;
+}
+
 const struct super_operations gfs2_super_ops = {
        .alloc_inode            = gfs2_alloc_inode,
        .free_inode             = gfs2_free_inode,