]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - fs/ocfs2/sysfile.c
Merge 'staging-next' to Linus's tree
[net-next-2.6.git] / fs / ocfs2 / sysfile.c
index bfe7190cdbf1b0969cc5e2ade3096a9cea16e9ad..902efb23b6a66cbe086e3d6f0b95fb883d6f95b2 100644 (file)
@@ -44,11 +44,6 @@ static struct inode * _ocfs2_get_system_file_inode(struct ocfs2_super *osb,
                                                   int type,
                                                   u32 slot);
 
-static inline int is_global_system_inode(int type);
-static inline int is_in_system_inode_array(struct ocfs2_super *osb,
-                                          int type,
-                                          u32 slot);
-
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 static struct lock_class_key ocfs2_sysfile_cluster_lock_key[NUM_SYSTEM_INODES];
 #endif
@@ -59,11 +54,52 @@ static inline int is_global_system_inode(int type)
                type <= OCFS2_LAST_GLOBAL_SYSTEM_INODE;
 }
 
-static inline int is_in_system_inode_array(struct ocfs2_super *osb,
-                                          int type,
-                                          u32 slot)
+static struct inode **get_local_system_inode(struct ocfs2_super *osb,
+                                            int type,
+                                            u32 slot)
 {
-       return slot == osb->slot_num || is_global_system_inode(type);
+       int index;
+       struct inode **local_system_inodes, **free = NULL;
+
+       BUG_ON(slot == OCFS2_INVALID_SLOT);
+       BUG_ON(type < OCFS2_FIRST_LOCAL_SYSTEM_INODE ||
+              type > OCFS2_LAST_LOCAL_SYSTEM_INODE);
+
+       spin_lock(&osb->osb_lock);
+       local_system_inodes = osb->local_system_inodes;
+       spin_unlock(&osb->osb_lock);
+
+       if (unlikely(!local_system_inodes)) {
+               local_system_inodes = kzalloc(sizeof(struct inode *) *
+                                             NUM_LOCAL_SYSTEM_INODES *
+                                             osb->max_slots,
+                                             GFP_NOFS);
+               if (!local_system_inodes) {
+                       mlog_errno(-ENOMEM);
+                       /*
+                        * return NULL here so that ocfs2_get_sytem_file_inodes
+                        * will try to create an inode and use it. We will try
+                        * to initialize local_system_inodes next time.
+                        */
+                       return NULL;
+               }
+
+               spin_lock(&osb->osb_lock);
+               if (osb->local_system_inodes) {
+                       /* Someone has initialized it for us. */
+                       free = local_system_inodes;
+                       local_system_inodes = osb->local_system_inodes;
+               } else
+                       osb->local_system_inodes = local_system_inodes;
+               spin_unlock(&osb->osb_lock);
+               if (unlikely(free))
+                       kfree(free);
+       }
+
+       index = (slot * NUM_LOCAL_SYSTEM_INODES) +
+               (type - OCFS2_FIRST_LOCAL_SYSTEM_INODE);
+
+       return &local_system_inodes[index];
 }
 
 struct inode *ocfs2_get_system_file_inode(struct ocfs2_super *osb,
@@ -74,8 +110,10 @@ struct inode *ocfs2_get_system_file_inode(struct ocfs2_super *osb,
        struct inode **arr = NULL;
 
        /* avoid the lookup if cached in local system file array */
-       if (is_in_system_inode_array(osb, type, slot))
-               arr = &(osb->system_inodes[type]);
+       if (is_global_system_inode(type)) {
+               arr = &(osb->global_system_inodes[type]);
+       } else
+               arr = get_local_system_inode(osb, type, slot);
 
        if (arr && ((inode = *arr) != NULL)) {
                /* get a ref in addition to the array ref */