ocfs2: remove ->unlock_ast() callback from ocfs2_lock_res_ops
[safe/jmp/linux-2.6] / fs / ocfs2 / dlmglue.c
index 764d15d..7532f80 100644 (file)
@@ -67,16 +67,12 @@ struct ocfs2_mask_waiter {
        unsigned long           mw_goal;
 };
 
-static void ocfs2_inode_ast_func(void *opaque);
 static void ocfs2_inode_bast_func(void *opaque,
                                  int level);
-static void ocfs2_dentry_ast_func(void *opaque);
 static void ocfs2_dentry_bast_func(void *opaque,
                                  int level);
-static void ocfs2_super_ast_func(void *opaque);
 static void ocfs2_super_bast_func(void *opaque,
                                  int level);
-static void ocfs2_rename_ast_func(void *opaque);
 static void ocfs2_rename_bast_func(void *opaque,
                                   int level);
 
@@ -100,9 +96,6 @@ struct ocfs2_unblock_ctl {
        enum ocfs2_unblock_action unblock_action;
 };
 
-/* so far, all locks have gotten along with the same unlock ast */
-static void ocfs2_unlock_ast_func(void *opaque,
-                                 enum dlm_status status);
 static int ocfs2_unblock_meta(struct ocfs2_lock_res *lockres,
                              struct ocfs2_unblock_ctl *ctl);
 static int ocfs2_unblock_data(struct ocfs2_lock_res *lockres,
@@ -117,14 +110,33 @@ static int ocfs2_unblock_osb_lock(struct ocfs2_lock_res *lockres,
 static void ocfs2_dentry_post_unlock(struct ocfs2_super *osb,
                                     struct ocfs2_lock_res *lockres);
 
+/*
+ * OCFS2 Lock Resource Operations
+ *
+ * These fine tune the behavior of the generic dlmglue locking infrastructure.
+ */
 struct ocfs2_lock_res_ops {
-       void (*ast)(void *);
        void (*bast)(void *, int);
-       void (*unlock_ast)(void *, enum dlm_status);
        int  (*unblock)(struct ocfs2_lock_res *, struct ocfs2_unblock_ctl *);
        void (*post_unlock)(struct ocfs2_super *, struct ocfs2_lock_res *);
+
+       /*
+        * LOCK_TYPE_* flags which describe the specific requirements
+        * of a lock type. Descriptions of each individual flag follow.
+        */
+       int flags;
 };
 
+/*
+ * Some locks want to "refresh" potentially stale data when a
+ * meaningful (PRMODE or EXMODE) lock level is first obtained. If this
+ * flag is set, the OCFS2_LOCK_NEEDS_REFRESH flag will be set on the
+ * individual lockres l_flags member from the ast function. It is
+ * expected that the locking wrapper will clear the
+ * OCFS2_LOCK_NEEDS_REFRESH flag when done.
+ */
+#define LOCK_TYPE_REQUIRES_REFRESH 0x1
+
 typedef int (ocfs2_convert_worker_t)(struct ocfs2_lock_res *, int);
 static int ocfs2_generic_unblock_lock(struct ocfs2_super *osb,
                                      struct ocfs2_lock_res *lockres,
@@ -132,46 +144,40 @@ static int ocfs2_generic_unblock_lock(struct ocfs2_super *osb,
                                      ocfs2_convert_worker_t *worker);
 
 static struct ocfs2_lock_res_ops ocfs2_inode_rw_lops = {
-       .ast            = ocfs2_inode_ast_func,
        .bast           = ocfs2_inode_bast_func,
-       .unlock_ast     = ocfs2_unlock_ast_func,
        .unblock        = ocfs2_unblock_inode_lock,
+       .flags          = 0,
 };
 
 static struct ocfs2_lock_res_ops ocfs2_inode_meta_lops = {
-       .ast            = ocfs2_inode_ast_func,
        .bast           = ocfs2_inode_bast_func,
-       .unlock_ast     = ocfs2_unlock_ast_func,
        .unblock        = ocfs2_unblock_meta,
+       .flags          = LOCK_TYPE_REQUIRES_REFRESH,
 };
 
 static struct ocfs2_lock_res_ops ocfs2_inode_data_lops = {
-       .ast            = ocfs2_inode_ast_func,
        .bast           = ocfs2_inode_bast_func,
-       .unlock_ast     = ocfs2_unlock_ast_func,
        .unblock        = ocfs2_unblock_data,
+       .flags          = 0,
 };
 
 static struct ocfs2_lock_res_ops ocfs2_super_lops = {
-       .ast            = ocfs2_super_ast_func,
        .bast           = ocfs2_super_bast_func,
-       .unlock_ast     = ocfs2_unlock_ast_func,
        .unblock        = ocfs2_unblock_osb_lock,
+       .flags          = LOCK_TYPE_REQUIRES_REFRESH,
 };
 
 static struct ocfs2_lock_res_ops ocfs2_rename_lops = {
-       .ast            = ocfs2_rename_ast_func,
        .bast           = ocfs2_rename_bast_func,
-       .unlock_ast     = ocfs2_unlock_ast_func,
        .unblock        = ocfs2_unblock_osb_lock,
+       .flags          = 0,
 };
 
 static struct ocfs2_lock_res_ops ocfs2_dentry_lops = {
-       .ast            = ocfs2_dentry_ast_func,
        .bast           = ocfs2_dentry_bast_func,
-       .unlock_ast     = ocfs2_unlock_ast_func,
        .unblock        = ocfs2_unblock_dentry_lock,
        .post_unlock    = ocfs2_dentry_post_unlock,
+       .flags          = 0,
 };
 
 static inline int ocfs2_is_inode_lock(struct ocfs2_lock_res *lockres)
@@ -320,6 +326,7 @@ void ocfs2_lock_res_init_once(struct ocfs2_lock_res *res)
 
 void ocfs2_inode_lock_res_init(struct ocfs2_lock_res *res,
                               enum ocfs2_lock_type type,
+                              unsigned int generation,
                               struct inode *inode)
 {
        struct ocfs2_lock_res_ops *ops;
@@ -341,7 +348,7 @@ void ocfs2_inode_lock_res_init(struct ocfs2_lock_res *res,
        };
 
        ocfs2_build_lock_name(type, OCFS2_I(inode)->ip_blkno,
-                             inode->i_generation, res->l_name);
+                             generation, res->l_name);
        ocfs2_lock_res_init_common(OCFS2_SB(inode->i_sb), res, type, ops, inode);
 }
 
@@ -568,7 +575,8 @@ static inline void ocfs2_generic_handle_convert_action(struct ocfs2_lock_res *lo
         * information is already up to data. Convert from NL to
         * *anything* however should mark ourselves as needing an
         * update */
-       if (lockres->l_level == LKM_NLMODE)
+       if (lockres->l_level == LKM_NLMODE &&
+           lockres->l_ops->flags & LOCK_TYPE_REQUIRES_REFRESH)
                lockres_or_flags(lockres, OCFS2_LOCK_NEEDS_REFRESH);
 
        lockres->l_level = lockres->l_requested;
@@ -585,7 +593,8 @@ static inline void ocfs2_generic_handle_attach_action(struct ocfs2_lock_res *loc
        BUG_ON(lockres->l_flags & OCFS2_LOCK_ATTACHED);
 
        if (lockres->l_requested > LKM_NLMODE &&
-           !(lockres->l_flags & OCFS2_LOCK_LOCAL))
+           !(lockres->l_flags & OCFS2_LOCK_LOCAL) &&
+           lockres->l_ops->flags & LOCK_TYPE_REQUIRES_REFRESH)
                lockres_or_flags(lockres, OCFS2_LOCK_NEEDS_REFRESH);
 
        lockres->l_level = lockres->l_requested;
@@ -595,68 +604,6 @@ static inline void ocfs2_generic_handle_attach_action(struct ocfs2_lock_res *loc
        mlog_exit_void();
 }
 
-static void ocfs2_inode_ast_func(void *opaque)
-{
-       struct ocfs2_lock_res *lockres = opaque;
-       struct inode *inode;
-       struct dlm_lockstatus *lksb;
-       unsigned long flags;
-
-       mlog_entry_void();
-
-       inode = ocfs2_lock_res_inode(lockres);
-
-       mlog(0, "AST fired for inode %llu, l_action = %u, type = %s\n",
-            (unsigned long long)OCFS2_I(inode)->ip_blkno, lockres->l_action,
-            ocfs2_lock_type_string(lockres->l_type));
-
-       BUG_ON(!ocfs2_is_inode_lock(lockres));
-
-       spin_lock_irqsave(&lockres->l_lock, flags);
-
-       lksb = &(lockres->l_lksb);
-       if (lksb->status != DLM_NORMAL) {
-               mlog(ML_ERROR, "ocfs2_inode_ast_func: lksb status value of %u "
-                    "on inode %llu\n", lksb->status,
-                    (unsigned long long)OCFS2_I(inode)->ip_blkno);
-               spin_unlock_irqrestore(&lockres->l_lock, flags);
-               mlog_exit_void();
-               return;
-       }
-
-       switch(lockres->l_action) {
-       case OCFS2_AST_ATTACH:
-               ocfs2_generic_handle_attach_action(lockres);
-               lockres_clear_flags(lockres, OCFS2_LOCK_LOCAL);
-               break;
-       case OCFS2_AST_CONVERT:
-               ocfs2_generic_handle_convert_action(lockres);
-               break;
-       case OCFS2_AST_DOWNCONVERT:
-               ocfs2_generic_handle_downconvert_action(lockres);
-               break;
-       default:
-               mlog(ML_ERROR, "lockres %s: ast fired with invalid action: %u "
-                    "lockres flags = 0x%lx, unlock action: %u\n",
-                    lockres->l_name, lockres->l_action, lockres->l_flags,
-                    lockres->l_unlock_action);
-
-               BUG();
-       }
-
-       /* data and rw locking ignores refresh flag for now. */
-       if (lockres->l_type != OCFS2_LOCK_TYPE_META)
-               lockres_clear_flags(lockres, OCFS2_LOCK_NEEDS_REFRESH);
-
-       /* set it to something invalid so if we get called again we
-        * can catch it. */
-       lockres->l_action = OCFS2_AST_INVALID;
-       spin_unlock_irqrestore(&lockres->l_lock, flags);
-       wake_up(&lockres->l_event);
-
-       mlog_exit_void();
-}
-
 static int ocfs2_generic_handle_bast(struct ocfs2_lock_res *lockres,
                                     int level)
 {
@@ -729,9 +676,9 @@ static void ocfs2_inode_bast_func(void *opaque, int level)
        mlog_exit_void();
 }
 
-static void ocfs2_generic_ast_func(struct ocfs2_lock_res *lockres,
-                                  int ignore_refresh)
+static void ocfs2_locking_ast(void *opaque)
 {
+       struct ocfs2_lock_res *lockres = opaque;
        struct dlm_lockstatus *lksb = &lockres->l_lksb;
        unsigned long flags;
 
@@ -747,6 +694,7 @@ static void ocfs2_generic_ast_func(struct ocfs2_lock_res *lockres,
        switch(lockres->l_action) {
        case OCFS2_AST_ATTACH:
                ocfs2_generic_handle_attach_action(lockres);
+               lockres_clear_flags(lockres, OCFS2_LOCK_LOCAL);
                break;
        case OCFS2_AST_CONVERT:
                ocfs2_generic_handle_convert_action(lockres);
@@ -755,12 +703,13 @@ static void ocfs2_generic_ast_func(struct ocfs2_lock_res *lockres,
                ocfs2_generic_handle_downconvert_action(lockres);
                break;
        default:
+               mlog(ML_ERROR, "lockres %s: ast fired with invalid action: %u "
+                    "lockres flags = 0x%lx, unlock action: %u\n",
+                    lockres->l_name, lockres->l_action, lockres->l_flags,
+                    lockres->l_unlock_action);
                BUG();
        }
 
-       if (ignore_refresh)
-               lockres_clear_flags(lockres, OCFS2_LOCK_NEEDS_REFRESH);
-
        /* set it to something invalid so if we get called again we
         * can catch it. */
        lockres->l_action = OCFS2_AST_INVALID;
@@ -769,19 +718,6 @@ static void ocfs2_generic_ast_func(struct ocfs2_lock_res *lockres,
        spin_unlock_irqrestore(&lockres->l_lock, flags);
 }
 
-static void ocfs2_super_ast_func(void *opaque)
-{
-       struct ocfs2_lock_res *lockres = opaque;
-
-       mlog_entry_void();
-       mlog(0, "Superblock AST fired\n");
-
-       BUG_ON(!ocfs2_is_super_lock(lockres));
-       ocfs2_generic_ast_func(lockres, 0);
-
-       mlog_exit_void();
-}
-
 static void ocfs2_super_bast_func(void *opaque,
                                  int level)
 {
@@ -798,21 +734,6 @@ static void ocfs2_super_bast_func(void *opaque,
        mlog_exit_void();
 }
 
-static void ocfs2_rename_ast_func(void *opaque)
-{
-       struct ocfs2_lock_res *lockres = opaque;
-
-       mlog_entry_void();
-
-       mlog(0, "Rename AST fired\n");
-
-       BUG_ON(!ocfs2_is_rename_lock(lockres));
-
-       ocfs2_generic_ast_func(lockres, 1);
-
-       mlog_exit_void();
-}
-
 static void ocfs2_rename_bast_func(void *opaque,
                                   int level)
 {
@@ -831,15 +752,6 @@ static void ocfs2_rename_bast_func(void *opaque,
        mlog_exit_void();
 }
 
-static void ocfs2_dentry_ast_func(void *opaque)
-{
-       struct ocfs2_lock_res *lockres = opaque;
-
-       BUG_ON(!lockres);
-
-       ocfs2_generic_ast_func(lockres, 1);
-}
-
 static void ocfs2_dentry_bast_func(void *opaque, int level)
 {
        struct ocfs2_lock_res *lockres = opaque;
@@ -906,7 +818,7 @@ static int ocfs2_lock_create(struct ocfs2_super *osb,
                         dlm_flags,
                         lockres->l_name,
                         OCFS2_LOCK_ID_MAX_LEN - 1,
-                        lockres->l_ops->ast,
+                        ocfs2_locking_ast,
                         lockres,
                         lockres->l_ops->bast);
        if (status != DLM_NORMAL) {
@@ -1096,7 +1008,7 @@ again:
                                 lkm_flags|LKM_CONVERT|LKM_VALBLK,
                                 lockres->l_name,
                                 OCFS2_LOCK_ID_MAX_LEN - 1,
-                                lockres->l_ops->ast,
+                                ocfs2_locking_ast,
                                 lockres,
                                 lockres->l_ops->bast);
                if (status != DLM_NORMAL) {
@@ -1173,17 +1085,19 @@ static void ocfs2_cluster_unlock(struct ocfs2_super *osb,
 
 int ocfs2_create_new_lock(struct ocfs2_super *osb,
                          struct ocfs2_lock_res *lockres,
-                         int ex)
+                         int ex,
+                         int local)
 {
        int level =  ex ? LKM_EXMODE : LKM_PRMODE;
        unsigned long flags;
+       int lkm_flags = local ? LKM_LOCAL : 0;
 
        spin_lock_irqsave(&lockres->l_lock, flags);
        BUG_ON(lockres->l_flags & OCFS2_LOCK_ATTACHED);
        lockres_or_flags(lockres, OCFS2_LOCK_LOCAL);
        spin_unlock_irqrestore(&lockres->l_lock, flags);
 
-       return ocfs2_lock_create(osb, lockres, level, LKM_LOCAL);
+       return ocfs2_lock_create(osb, lockres, level, lkm_flags);
 }
 
 /* Grants us an EX lock on the data and metadata resources, skipping
@@ -1212,19 +1126,23 @@ int ocfs2_create_new_inode_locks(struct inode *inode)
         * on a resource which has an invalid one -- we'll set it
         * valid when we release the EX. */
 
-       ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_rw_lockres, 1);
+       ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_rw_lockres, 1, 1);
        if (ret) {
                mlog_errno(ret);
                goto bail;
        }
 
-       ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_meta_lockres, 1);
+       /*
+        * We don't want to use LKM_LOCAL on a meta data lock as they
+        * don't use a generation in their lock names.
+        */
+       ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_meta_lockres, 1, 0);
        if (ret) {
                mlog_errno(ret);
                goto bail;
        }
 
-       ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_data_lockres, 1);
+       ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_data_lockres, 1, 1);
        if (ret) {
                mlog_errno(ret);
                goto bail;
@@ -1413,7 +1331,17 @@ static void __ocfs2_stuff_meta_lvb(struct inode *inode)
 
        lvb = (struct ocfs2_meta_lvb *) lockres->l_lksb.lvb;
 
-       lvb->lvb_version   = cpu_to_be32(OCFS2_LVB_VERSION);
+       /*
+        * Invalidate the LVB of a deleted inode - this way other
+        * nodes are forced to go to disk and discover the new inode
+        * status.
+        */
+       if (oi->ip_flags & OCFS2_INODE_DELETED) {
+               lvb->lvb_version = 0;
+               goto out;
+       }
+
+       lvb->lvb_version   = OCFS2_LVB_VERSION;
        lvb->lvb_isize     = cpu_to_be64(i_size_read(inode));
        lvb->lvb_iclusters = cpu_to_be32(oi->ip_clusters);
        lvb->lvb_iuid      = cpu_to_be32(inode->i_uid);
@@ -1427,7 +1355,9 @@ static void __ocfs2_stuff_meta_lvb(struct inode *inode)
        lvb->lvb_imtime_packed =
                cpu_to_be64(ocfs2_pack_timespec(&inode->i_mtime));
        lvb->lvb_iattr    = cpu_to_be32(oi->ip_attr);
+       lvb->lvb_igeneration = cpu_to_be32(inode->i_generation);
 
+out:
        mlog_meta_lvb(0, lockres);
 
        mlog_exit_void();
@@ -1482,11 +1412,13 @@ static void ocfs2_refresh_inode_from_lvb(struct inode *inode)
        mlog_exit_void();
 }
 
-static inline int ocfs2_meta_lvb_is_trustable(struct ocfs2_lock_res *lockres)
+static inline int ocfs2_meta_lvb_is_trustable(struct inode *inode,
+                                             struct ocfs2_lock_res *lockres)
 {
        struct ocfs2_meta_lvb *lvb = (struct ocfs2_meta_lvb *) lockres->l_lksb.lvb;
 
-       if (be32_to_cpu(lvb->lvb_version) == OCFS2_LVB_VERSION)
+       if (lvb->lvb_version == OCFS2_LVB_VERSION
+           && be32_to_cpu(lvb->lvb_igeneration) == inode->i_generation)
                return 1;
        return 0;
 }
@@ -1583,7 +1515,7 @@ static int ocfs2_meta_lock_update(struct inode *inode,
         * map (directories, bitmap files, etc) */
        ocfs2_extent_map_trunc(inode, 0);
 
-       if (ocfs2_meta_lvb_is_trustable(lockres)) {
+       if (ocfs2_meta_lvb_is_trustable(inode, lockres)) {
                mlog(0, "Trusting LVB on inode %llu\n",
                     (unsigned long long)oi->ip_blkno);
                ocfs2_refresh_inode_from_lvb(inode);
@@ -1724,6 +1656,18 @@ int ocfs2_meta_lock_full(struct inode *inode,
                wait_event(osb->recovery_event,
                           ocfs2_node_map_is_empty(osb, &osb->recovery_map));
 
+       /*
+        * We only see this flag if we're being called from
+        * ocfs2_read_locked_inode(). It means we're locking an inode
+        * which hasn't been populated yet, so clear the refresh flag
+        * and let the caller handle it.
+        */
+       if (inode->i_state & I_NEW) {
+               status = 0;
+               ocfs2_complete_lock_res_refresh(lockres, 0);
+               goto bail;
+       }
+
        /* This is fun. The caller may want a bh back, or it may
         * not. ocfs2_meta_lock_update definitely wants one in, but
         * may or may not read one, depending on what's in the
@@ -2267,7 +2211,7 @@ void ocfs2_dlm_shutdown(struct ocfs2_super *osb)
        mlog_exit_void();
 }
 
-static void ocfs2_unlock_ast_func(void *opaque, enum dlm_status status)
+static void ocfs2_unlock_ast(void *opaque, enum dlm_status status)
 {
        struct ocfs2_lock_res *lockres = opaque;
        unsigned long flags;
@@ -2391,7 +2335,7 @@ static int ocfs2_drop_lock(struct ocfs2_super *osb,
        mlog(0, "lock %s\n", lockres->l_name);
 
        status = dlmunlock(osb->dlm, &lockres->l_lksb, LKM_VALBLK,
-                          lockres->l_ops->unlock_ast, lockres);
+                          ocfs2_unlock_ast, lockres);
        if (status != DLM_NORMAL) {
                ocfs2_log_dlm_error("dlmunlock", status, lockres);
                mlog(ML_ERROR, "lockres flags: %lu\n", lockres->l_flags);
@@ -2545,7 +2489,7 @@ static int ocfs2_downconvert_lock(struct ocfs2_super *osb,
                         dlm_flags,
                         lockres->l_name,
                         OCFS2_LOCK_ID_MAX_LEN - 1,
-                        lockres->l_ops->ast,
+                        ocfs2_locking_ast,
                         lockres,
                         lockres->l_ops->bast);
        if (status != DLM_NORMAL) {
@@ -2606,7 +2550,7 @@ static int ocfs2_cancel_convert(struct ocfs2_super *osb,
        status = dlmunlock(osb->dlm,
                           &lockres->l_lksb,
                           LKM_CANCEL,
-                          lockres->l_ops->unlock_ast,
+                          ocfs2_unlock_ast,
                           lockres);
        if (status != DLM_NORMAL) {
                ocfs2_log_dlm_error("dlmunlock", status, lockres);
@@ -3166,8 +3110,9 @@ void ocfs2_dump_meta_lvb_info(u64 level,
 
        mlog(level, "LVB information for %s (called from %s:%u):\n",
             lockres->l_name, function, line);
-       mlog(level, "version: %u, clusters: %u\n",
-            be32_to_cpu(lvb->lvb_version), be32_to_cpu(lvb->lvb_iclusters));
+       mlog(level, "version: %u, clusters: %u, generation: 0x%x\n",
+            lvb->lvb_version, be32_to_cpu(lvb->lvb_iclusters),
+            be32_to_cpu(lvb->lvb_igeneration));
        mlog(level, "size: %llu, uid %u, gid %u, mode 0x%x\n",
             (unsigned long long)be64_to_cpu(lvb->lvb_isize),
             be32_to_cpu(lvb->lvb_iuid), be32_to_cpu(lvb->lvb_igid),