diff options
-rw-r--r-- | fs/ocfs2/cluster/tcp_internal.h | 11 | ||||
-rw-r--r-- | fs/ocfs2/dlm/dlmapi.h | 7 | ||||
-rw-r--r-- | fs/ocfs2/dlm/dlmcommon.h | 24 | ||||
-rw-r--r-- | fs/ocfs2/dlm/dlmdomain.c | 195 | ||||
-rw-r--r-- | fs/ocfs2/dlm/dlmfs.c | 15 | ||||
-rw-r--r-- | fs/ocfs2/dlm/userdlm.c | 5 | ||||
-rw-r--r-- | fs/ocfs2/dlm/userdlm.h | 3 | ||||
-rw-r--r-- | fs/ocfs2/dlmglue.c | 29 | ||||
-rw-r--r-- | fs/ocfs2/dlmglue.h | 1 | ||||
-rw-r--r-- | fs/ocfs2/ocfs2.h | 1 | ||||
-rw-r--r-- | fs/ocfs2/ocfs2_lockingver.h | 30 | ||||
-rw-r--r-- | fs/ocfs2/super.c | 1 |
12 files changed, 288 insertions, 34 deletions
diff --git a/fs/ocfs2/cluster/tcp_internal.h b/fs/ocfs2/cluster/tcp_internal.h index b2e832aca567..d25b9af28500 100644 --- a/fs/ocfs2/cluster/tcp_internal.h +++ b/fs/ocfs2/cluster/tcp_internal.h | |||
@@ -38,6 +38,15 @@ | |||
38 | * locking semantics of the file system using the protocol. It should | 38 | * locking semantics of the file system using the protocol. It should |
39 | * be somewhere else, I'm sure, but right now it isn't. | 39 | * be somewhere else, I'm sure, but right now it isn't. |
40 | * | 40 | * |
41 | * With version 11, we separate out the filesystem locking portion. The | ||
42 | * filesystem now has a major.minor version it negotiates. Version 11 | ||
43 | * introduces this negotiation to the o2dlm protocol, and as such the | ||
44 | * version here in tcp_internal.h should not need to be bumped for | ||
45 | * filesystem locking changes. | ||
46 | * | ||
47 | * New in version 11 | ||
48 | * - Negotiation of filesystem locking in the dlm join. | ||
49 | * | ||
41 | * New in version 10: | 50 | * New in version 10: |
42 | * - Meta/data locks combined | 51 | * - Meta/data locks combined |
43 | * | 52 | * |
@@ -66,7 +75,7 @@ | |||
66 | * - full 64 bit i_size in the metadata lock lvbs | 75 | * - full 64 bit i_size in the metadata lock lvbs |
67 | * - introduction of "rw" lock and pushing meta/data locking down | 76 | * - introduction of "rw" lock and pushing meta/data locking down |
68 | */ | 77 | */ |
69 | #define O2NET_PROTOCOL_VERSION 10ULL | 78 | #define O2NET_PROTOCOL_VERSION 11ULL |
70 | struct o2net_handshake { | 79 | struct o2net_handshake { |
71 | __be64 protocol_version; | 80 | __be64 protocol_version; |
72 | __be64 connector_id; | 81 | __be64 connector_id; |
diff --git a/fs/ocfs2/dlm/dlmapi.h b/fs/ocfs2/dlm/dlmapi.h index cfd5cb65cab0..b5786a787fab 100644 --- a/fs/ocfs2/dlm/dlmapi.h +++ b/fs/ocfs2/dlm/dlmapi.h | |||
@@ -193,7 +193,12 @@ enum dlm_status dlmunlock(struct dlm_ctxt *dlm, | |||
193 | dlm_astunlockfunc_t *unlockast, | 193 | dlm_astunlockfunc_t *unlockast, |
194 | void *data); | 194 | void *data); |
195 | 195 | ||
196 | struct dlm_ctxt * dlm_register_domain(const char *domain, u32 key); | 196 | struct dlm_protocol_version { |
197 | u8 pv_major; | ||
198 | u8 pv_minor; | ||
199 | }; | ||
200 | struct dlm_ctxt * dlm_register_domain(const char *domain, u32 key, | ||
201 | struct dlm_protocol_version *fs_proto); | ||
197 | 202 | ||
198 | void dlm_unregister_domain(struct dlm_ctxt *dlm); | 203 | void dlm_unregister_domain(struct dlm_ctxt *dlm); |
199 | 204 | ||
diff --git a/fs/ocfs2/dlm/dlmcommon.h b/fs/ocfs2/dlm/dlmcommon.h index e90b92f9ece1..9843ee17ea27 100644 --- a/fs/ocfs2/dlm/dlmcommon.h +++ b/fs/ocfs2/dlm/dlmcommon.h | |||
@@ -142,6 +142,12 @@ struct dlm_ctxt | |||
142 | spinlock_t work_lock; | 142 | spinlock_t work_lock; |
143 | struct list_head dlm_domain_handlers; | 143 | struct list_head dlm_domain_handlers; |
144 | struct list_head dlm_eviction_callbacks; | 144 | struct list_head dlm_eviction_callbacks; |
145 | |||
146 | /* The filesystem specifies this at domain registration. We | ||
147 | * cache it here to know what to tell other nodes. */ | ||
148 | struct dlm_protocol_version fs_locking_proto; | ||
149 | /* This is the inter-dlm communication version */ | ||
150 | struct dlm_protocol_version dlm_locking_proto; | ||
145 | }; | 151 | }; |
146 | 152 | ||
147 | static inline struct hlist_head *dlm_lockres_hash(struct dlm_ctxt *dlm, unsigned i) | 153 | static inline struct hlist_head *dlm_lockres_hash(struct dlm_ctxt *dlm, unsigned i) |
@@ -589,10 +595,24 @@ struct dlm_proxy_ast | |||
589 | #define DLM_PROXY_AST_MAX_LEN (sizeof(struct dlm_proxy_ast)+DLM_LVB_LEN) | 595 | #define DLM_PROXY_AST_MAX_LEN (sizeof(struct dlm_proxy_ast)+DLM_LVB_LEN) |
590 | 596 | ||
591 | #define DLM_MOD_KEY (0x666c6172) | 597 | #define DLM_MOD_KEY (0x666c6172) |
592 | enum dlm_query_join_response { | 598 | enum dlm_query_join_response_code { |
593 | JOIN_DISALLOW = 0, | 599 | JOIN_DISALLOW = 0, |
594 | JOIN_OK, | 600 | JOIN_OK, |
595 | JOIN_OK_NO_MAP, | 601 | JOIN_OK_NO_MAP, |
602 | JOIN_PROTOCOL_MISMATCH, | ||
603 | }; | ||
604 | |||
605 | union dlm_query_join_response { | ||
606 | u32 intval; | ||
607 | struct { | ||
608 | u8 code; /* Response code. dlm_minor and fs_minor | ||
609 | are only valid if this is JOIN_OK */ | ||
610 | u8 dlm_minor; /* The minor version of the protocol the | ||
611 | dlm is speaking. */ | ||
612 | u8 fs_minor; /* The minor version of the protocol the | ||
613 | filesystem is speaking. */ | ||
614 | u8 reserved; | ||
615 | } packet; | ||
596 | }; | 616 | }; |
597 | 617 | ||
598 | struct dlm_lock_request | 618 | struct dlm_lock_request |
@@ -633,6 +653,8 @@ struct dlm_query_join_request | |||
633 | u8 node_idx; | 653 | u8 node_idx; |
634 | u8 pad1[2]; | 654 | u8 pad1[2]; |
635 | u8 name_len; | 655 | u8 name_len; |
656 | struct dlm_protocol_version dlm_proto; | ||
657 | struct dlm_protocol_version fs_proto; | ||
636 | u8 domain[O2NM_MAX_NAME_LEN]; | 658 | u8 domain[O2NM_MAX_NAME_LEN]; |
637 | u8 node_map[BITS_TO_BYTES(O2NM_MAX_NODES)]; | 659 | u8 node_map[BITS_TO_BYTES(O2NM_MAX_NODES)]; |
638 | }; | 660 | }; |
diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c index 6954565b8ccb..638d2ebb892b 100644 --- a/fs/ocfs2/dlm/dlmdomain.c +++ b/fs/ocfs2/dlm/dlmdomain.c | |||
@@ -123,6 +123,17 @@ DEFINE_SPINLOCK(dlm_domain_lock); | |||
123 | LIST_HEAD(dlm_domains); | 123 | LIST_HEAD(dlm_domains); |
124 | static DECLARE_WAIT_QUEUE_HEAD(dlm_domain_events); | 124 | static DECLARE_WAIT_QUEUE_HEAD(dlm_domain_events); |
125 | 125 | ||
126 | /* | ||
127 | * The supported protocol version for DLM communication. Running domains | ||
128 | * will have a negotiated version with the same major number and a minor | ||
129 | * number equal or smaller. The dlm_ctxt->dlm_locking_proto field should | ||
130 | * be used to determine what a running domain is actually using. | ||
131 | */ | ||
132 | static const struct dlm_protocol_version dlm_protocol = { | ||
133 | .pv_major = 1, | ||
134 | .pv_minor = 0, | ||
135 | }; | ||
136 | |||
126 | #define DLM_DOMAIN_BACKOFF_MS 200 | 137 | #define DLM_DOMAIN_BACKOFF_MS 200 |
127 | 138 | ||
128 | static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data, | 139 | static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data, |
@@ -133,6 +144,8 @@ static int dlm_cancel_join_handler(struct o2net_msg *msg, u32 len, void *data, | |||
133 | void **ret_data); | 144 | void **ret_data); |
134 | static int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data, | 145 | static int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data, |
135 | void **ret_data); | 146 | void **ret_data); |
147 | static int dlm_protocol_compare(struct dlm_protocol_version *existing, | ||
148 | struct dlm_protocol_version *request); | ||
136 | 149 | ||
137 | static void dlm_unregister_domain_handlers(struct dlm_ctxt *dlm); | 150 | static void dlm_unregister_domain_handlers(struct dlm_ctxt *dlm); |
138 | 151 | ||
@@ -668,11 +681,45 @@ void dlm_unregister_domain(struct dlm_ctxt *dlm) | |||
668 | } | 681 | } |
669 | EXPORT_SYMBOL_GPL(dlm_unregister_domain); | 682 | EXPORT_SYMBOL_GPL(dlm_unregister_domain); |
670 | 683 | ||
684 | static int dlm_query_join_proto_check(char *proto_type, int node, | ||
685 | struct dlm_protocol_version *ours, | ||
686 | struct dlm_protocol_version *request) | ||
687 | { | ||
688 | int rc; | ||
689 | struct dlm_protocol_version proto = *request; | ||
690 | |||
691 | if (!dlm_protocol_compare(ours, &proto)) { | ||
692 | mlog(0, | ||
693 | "node %u wanted to join with %s locking protocol " | ||
694 | "%u.%u, we respond with %u.%u\n", | ||
695 | node, proto_type, | ||
696 | request->pv_major, | ||
697 | request->pv_minor, | ||
698 | proto.pv_major, proto.pv_minor); | ||
699 | request->pv_minor = proto.pv_minor; | ||
700 | rc = 0; | ||
701 | } else { | ||
702 | mlog(ML_NOTICE, | ||
703 | "Node %u wanted to join with %s locking " | ||
704 | "protocol %u.%u, but we have %u.%u, disallowing\n", | ||
705 | node, proto_type, | ||
706 | request->pv_major, | ||
707 | request->pv_minor, | ||
708 | ours->pv_major, | ||
709 | ours->pv_minor); | ||
710 | rc = 1; | ||
711 | } | ||
712 | |||
713 | return rc; | ||
714 | } | ||
715 | |||
671 | static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data, | 716 | static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data, |
672 | void **ret_data) | 717 | void **ret_data) |
673 | { | 718 | { |
674 | struct dlm_query_join_request *query; | 719 | struct dlm_query_join_request *query; |
675 | enum dlm_query_join_response response; | 720 | union dlm_query_join_response response = { |
721 | .packet.code = JOIN_DISALLOW, | ||
722 | }; | ||
676 | struct dlm_ctxt *dlm = NULL; | 723 | struct dlm_ctxt *dlm = NULL; |
677 | u8 nodenum; | 724 | u8 nodenum; |
678 | 725 | ||
@@ -690,11 +737,11 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data, | |||
690 | mlog(0, "node %u is not in our live map yet\n", | 737 | mlog(0, "node %u is not in our live map yet\n", |
691 | query->node_idx); | 738 | query->node_idx); |
692 | 739 | ||
693 | response = JOIN_DISALLOW; | 740 | response.packet.code = JOIN_DISALLOW; |
694 | goto respond; | 741 | goto respond; |
695 | } | 742 | } |
696 | 743 | ||
697 | response = JOIN_OK_NO_MAP; | 744 | response.packet.code = JOIN_OK_NO_MAP; |
698 | 745 | ||
699 | spin_lock(&dlm_domain_lock); | 746 | spin_lock(&dlm_domain_lock); |
700 | dlm = __dlm_lookup_domain_full(query->domain, query->name_len); | 747 | dlm = __dlm_lookup_domain_full(query->domain, query->name_len); |
@@ -713,7 +760,7 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data, | |||
713 | mlog(0, "disallow join as node %u does not " | 760 | mlog(0, "disallow join as node %u does not " |
714 | "have node %u in its nodemap\n", | 761 | "have node %u in its nodemap\n", |
715 | query->node_idx, nodenum); | 762 | query->node_idx, nodenum); |
716 | response = JOIN_DISALLOW; | 763 | response.packet.code = JOIN_DISALLOW; |
717 | goto unlock_respond; | 764 | goto unlock_respond; |
718 | } | 765 | } |
719 | } | 766 | } |
@@ -733,30 +780,48 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data, | |||
733 | /*If this is a brand new context and we | 780 | /*If this is a brand new context and we |
734 | * haven't started our join process yet, then | 781 | * haven't started our join process yet, then |
735 | * the other node won the race. */ | 782 | * the other node won the race. */ |
736 | response = JOIN_OK_NO_MAP; | 783 | response.packet.code = JOIN_OK_NO_MAP; |
737 | } else if (dlm->joining_node != DLM_LOCK_RES_OWNER_UNKNOWN) { | 784 | } else if (dlm->joining_node != DLM_LOCK_RES_OWNER_UNKNOWN) { |
738 | /* Disallow parallel joins. */ | 785 | /* Disallow parallel joins. */ |
739 | response = JOIN_DISALLOW; | 786 | response.packet.code = JOIN_DISALLOW; |
740 | } else if (dlm->reco.state & DLM_RECO_STATE_ACTIVE) { | 787 | } else if (dlm->reco.state & DLM_RECO_STATE_ACTIVE) { |
741 | mlog(0, "node %u trying to join, but recovery " | 788 | mlog(0, "node %u trying to join, but recovery " |
742 | "is ongoing.\n", bit); | 789 | "is ongoing.\n", bit); |
743 | response = JOIN_DISALLOW; | 790 | response.packet.code = JOIN_DISALLOW; |
744 | } else if (test_bit(bit, dlm->recovery_map)) { | 791 | } else if (test_bit(bit, dlm->recovery_map)) { |
745 | mlog(0, "node %u trying to join, but it " | 792 | mlog(0, "node %u trying to join, but it " |
746 | "still needs recovery.\n", bit); | 793 | "still needs recovery.\n", bit); |
747 | response = JOIN_DISALLOW; | 794 | response.packet.code = JOIN_DISALLOW; |
748 | } else if (test_bit(bit, dlm->domain_map)) { | 795 | } else if (test_bit(bit, dlm->domain_map)) { |
749 | mlog(0, "node %u trying to join, but it " | 796 | mlog(0, "node %u trying to join, but it " |
750 | "is still in the domain! needs recovery?\n", | 797 | "is still in the domain! needs recovery?\n", |
751 | bit); | 798 | bit); |
752 | response = JOIN_DISALLOW; | 799 | response.packet.code = JOIN_DISALLOW; |
753 | } else { | 800 | } else { |
754 | /* Alright we're fully a part of this domain | 801 | /* Alright we're fully a part of this domain |
755 | * so we keep some state as to who's joining | 802 | * so we keep some state as to who's joining |
756 | * and indicate to him that needs to be fixed | 803 | * and indicate to him that needs to be fixed |
757 | * up. */ | 804 | * up. */ |
758 | response = JOIN_OK; | 805 | |
759 | __dlm_set_joining_node(dlm, query->node_idx); | 806 | /* Make sure we speak compatible locking protocols. */ |
807 | if (dlm_query_join_proto_check("DLM", bit, | ||
808 | &dlm->dlm_locking_proto, | ||
809 | &query->dlm_proto)) { | ||
810 | response.packet.code = | ||
811 | JOIN_PROTOCOL_MISMATCH; | ||
812 | } else if (dlm_query_join_proto_check("fs", bit, | ||
813 | &dlm->fs_locking_proto, | ||
814 | &query->fs_proto)) { | ||
815 | response.packet.code = | ||
816 | JOIN_PROTOCOL_MISMATCH; | ||
817 | } else { | ||
818 | response.packet.dlm_minor = | ||
819 | query->dlm_proto.pv_minor; | ||
820 | response.packet.fs_minor = | ||
821 | query->fs_proto.pv_minor; | ||
822 | response.packet.code = JOIN_OK; | ||
823 | __dlm_set_joining_node(dlm, query->node_idx); | ||
824 | } | ||
760 | } | 825 | } |
761 | 826 | ||
762 | spin_unlock(&dlm->spinlock); | 827 | spin_unlock(&dlm->spinlock); |
@@ -765,9 +830,9 @@ unlock_respond: | |||
765 | spin_unlock(&dlm_domain_lock); | 830 | spin_unlock(&dlm_domain_lock); |
766 | 831 | ||
767 | respond: | 832 | respond: |
768 | mlog(0, "We respond with %u\n", response); | 833 | mlog(0, "We respond with %u\n", response.packet.code); |
769 | 834 | ||
770 | return response; | 835 | return response.intval; |
771 | } | 836 | } |
772 | 837 | ||
773 | static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data, | 838 | static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data, |
@@ -899,10 +964,11 @@ static int dlm_send_join_cancels(struct dlm_ctxt *dlm, | |||
899 | 964 | ||
900 | static int dlm_request_join(struct dlm_ctxt *dlm, | 965 | static int dlm_request_join(struct dlm_ctxt *dlm, |
901 | int node, | 966 | int node, |
902 | enum dlm_query_join_response *response) | 967 | enum dlm_query_join_response_code *response) |
903 | { | 968 | { |
904 | int status, retval; | 969 | int status; |
905 | struct dlm_query_join_request join_msg; | 970 | struct dlm_query_join_request join_msg; |
971 | union dlm_query_join_response join_resp; | ||
906 | 972 | ||
907 | mlog(0, "querying node %d\n", node); | 973 | mlog(0, "querying node %d\n", node); |
908 | 974 | ||
@@ -910,12 +976,15 @@ static int dlm_request_join(struct dlm_ctxt *dlm, | |||
910 | join_msg.node_idx = dlm->node_num; | 976 | join_msg.node_idx = dlm->node_num; |
911 | join_msg.name_len = strlen(dlm->name); | 977 | join_msg.name_len = strlen(dlm->name); |
912 | memcpy(join_msg.domain, dlm->name, join_msg.name_len); | 978 | memcpy(join_msg.domain, dlm->name, join_msg.name_len); |
979 | join_msg.dlm_proto = dlm->dlm_locking_proto; | ||
980 | join_msg.fs_proto = dlm->fs_locking_proto; | ||
913 | 981 | ||
914 | /* copy live node map to join message */ | 982 | /* copy live node map to join message */ |
915 | byte_copymap(join_msg.node_map, dlm->live_nodes_map, O2NM_MAX_NODES); | 983 | byte_copymap(join_msg.node_map, dlm->live_nodes_map, O2NM_MAX_NODES); |
916 | 984 | ||
917 | status = o2net_send_message(DLM_QUERY_JOIN_MSG, DLM_MOD_KEY, &join_msg, | 985 | status = o2net_send_message(DLM_QUERY_JOIN_MSG, DLM_MOD_KEY, &join_msg, |
918 | sizeof(join_msg), node, &retval); | 986 | sizeof(join_msg), node, |
987 | &join_resp.intval); | ||
919 | if (status < 0 && status != -ENOPROTOOPT) { | 988 | if (status < 0 && status != -ENOPROTOOPT) { |
920 | mlog_errno(status); | 989 | mlog_errno(status); |
921 | goto bail; | 990 | goto bail; |
@@ -928,14 +997,41 @@ static int dlm_request_join(struct dlm_ctxt *dlm, | |||
928 | if (status == -ENOPROTOOPT) { | 997 | if (status == -ENOPROTOOPT) { |
929 | status = 0; | 998 | status = 0; |
930 | *response = JOIN_OK_NO_MAP; | 999 | *response = JOIN_OK_NO_MAP; |
931 | } else if (retval == JOIN_DISALLOW || | 1000 | } else if (join_resp.packet.code == JOIN_DISALLOW || |
932 | retval == JOIN_OK || | 1001 | join_resp.packet.code == JOIN_OK_NO_MAP) { |
933 | retval == JOIN_OK_NO_MAP) { | 1002 | *response = join_resp.packet.code; |
934 | *response = retval; | 1003 | } else if (join_resp.packet.code == JOIN_PROTOCOL_MISMATCH) { |
1004 | mlog(ML_NOTICE, | ||
1005 | "This node requested DLM locking protocol %u.%u and " | ||
1006 | "filesystem locking protocol %u.%u. At least one of " | ||
1007 | "the protocol versions on node %d is not compatible, " | ||
1008 | "disconnecting\n", | ||
1009 | dlm->dlm_locking_proto.pv_major, | ||
1010 | dlm->dlm_locking_proto.pv_minor, | ||
1011 | dlm->fs_locking_proto.pv_major, | ||
1012 | dlm->fs_locking_proto.pv_minor, | ||
1013 | node); | ||
1014 | status = -EPROTO; | ||
1015 | *response = join_resp.packet.code; | ||
1016 | } else if (join_resp.packet.code == JOIN_OK) { | ||
1017 | *response = join_resp.packet.code; | ||
1018 | /* Use the same locking protocol as the remote node */ | ||
1019 | dlm->dlm_locking_proto.pv_minor = | ||
1020 | join_resp.packet.dlm_minor; | ||
1021 | dlm->fs_locking_proto.pv_minor = | ||
1022 | join_resp.packet.fs_minor; | ||
1023 | mlog(0, | ||
1024 | "Node %d responds JOIN_OK with DLM locking protocol " | ||
1025 | "%u.%u and fs locking protocol %u.%u\n", | ||
1026 | node, | ||
1027 | dlm->dlm_locking_proto.pv_major, | ||
1028 | dlm->dlm_locking_proto.pv_minor, | ||
1029 | dlm->fs_locking_proto.pv_major, | ||
1030 | dlm->fs_locking_proto.pv_minor); | ||
935 | } else { | 1031 | } else { |
936 | status = -EINVAL; | 1032 | status = -EINVAL; |
937 | mlog(ML_ERROR, "invalid response %d from node %u\n", retval, | 1033 | mlog(ML_ERROR, "invalid response %d from node %u\n", |
938 | node); | 1034 | join_resp.packet.code, node); |
939 | } | 1035 | } |
940 | 1036 | ||
941 | mlog(0, "status %d, node %d response is %d\n", status, node, | 1037 | mlog(0, "status %d, node %d response is %d\n", status, node, |
@@ -1008,7 +1104,7 @@ struct domain_join_ctxt { | |||
1008 | 1104 | ||
1009 | static int dlm_should_restart_join(struct dlm_ctxt *dlm, | 1105 | static int dlm_should_restart_join(struct dlm_ctxt *dlm, |
1010 | struct domain_join_ctxt *ctxt, | 1106 | struct domain_join_ctxt *ctxt, |
1011 | enum dlm_query_join_response response) | 1107 | enum dlm_query_join_response_code response) |
1012 | { | 1108 | { |
1013 | int ret; | 1109 | int ret; |
1014 | 1110 | ||
@@ -1034,7 +1130,7 @@ static int dlm_try_to_join_domain(struct dlm_ctxt *dlm) | |||
1034 | { | 1130 | { |
1035 | int status = 0, tmpstat, node; | 1131 | int status = 0, tmpstat, node; |
1036 | struct domain_join_ctxt *ctxt; | 1132 | struct domain_join_ctxt *ctxt; |
1037 | enum dlm_query_join_response response = JOIN_DISALLOW; | 1133 | enum dlm_query_join_response_code response = JOIN_DISALLOW; |
1038 | 1134 | ||
1039 | mlog_entry("%p", dlm); | 1135 | mlog_entry("%p", dlm); |
1040 | 1136 | ||
@@ -1450,10 +1546,38 @@ leave: | |||
1450 | } | 1546 | } |
1451 | 1547 | ||
1452 | /* | 1548 | /* |
1453 | * dlm_register_domain: one-time setup per "domain" | 1549 | * Compare a requested locking protocol version against the current one. |
1550 | * | ||
1551 | * If the major numbers are different, they are incompatible. | ||
1552 | * If the current minor is greater than the request, they are incompatible. | ||
1553 | * If the current minor is less than or equal to the request, they are | ||
1554 | * compatible, and the requester should run at the current minor version. | ||
1555 | */ | ||
1556 | static int dlm_protocol_compare(struct dlm_protocol_version *existing, | ||
1557 | struct dlm_protocol_version *request) | ||
1558 | { | ||
1559 | if (existing->pv_major != request->pv_major) | ||
1560 | return 1; | ||
1561 | |||
1562 | if (existing->pv_minor > request->pv_minor) | ||
1563 | return 1; | ||
1564 | |||
1565 | if (existing->pv_minor < request->pv_minor) | ||
1566 | request->pv_minor = existing->pv_minor; | ||
1567 | |||
1568 | return 0; | ||
1569 | } | ||
1570 | |||
1571 | /* | ||
1572 | * dlm_register_domain: one-time setup per "domain". | ||
1573 | * | ||
1574 | * The filesystem passes in the requested locking version via proto. | ||
1575 | * If registration was successful, proto will contain the negotiated | ||
1576 | * locking protocol. | ||
1454 | */ | 1577 | */ |
1455 | struct dlm_ctxt * dlm_register_domain(const char *domain, | 1578 | struct dlm_ctxt * dlm_register_domain(const char *domain, |
1456 | u32 key) | 1579 | u32 key, |
1580 | struct dlm_protocol_version *fs_proto) | ||
1457 | { | 1581 | { |
1458 | int ret; | 1582 | int ret; |
1459 | struct dlm_ctxt *dlm = NULL; | 1583 | struct dlm_ctxt *dlm = NULL; |
@@ -1496,6 +1620,15 @@ retry: | |||
1496 | goto retry; | 1620 | goto retry; |
1497 | } | 1621 | } |
1498 | 1622 | ||
1623 | if (dlm_protocol_compare(&dlm->fs_locking_proto, fs_proto)) { | ||
1624 | mlog(ML_ERROR, | ||
1625 | "Requested locking protocol version is not " | ||
1626 | "compatible with already registered domain " | ||
1627 | "\"%s\"\n", domain); | ||
1628 | ret = -EPROTO; | ||
1629 | goto leave; | ||
1630 | } | ||
1631 | |||
1499 | __dlm_get(dlm); | 1632 | __dlm_get(dlm); |
1500 | dlm->num_joins++; | 1633 | dlm->num_joins++; |
1501 | 1634 | ||
@@ -1526,6 +1659,13 @@ retry: | |||
1526 | list_add_tail(&dlm->list, &dlm_domains); | 1659 | list_add_tail(&dlm->list, &dlm_domains); |
1527 | spin_unlock(&dlm_domain_lock); | 1660 | spin_unlock(&dlm_domain_lock); |
1528 | 1661 | ||
1662 | /* | ||
1663 | * Pass the locking protocol version into the join. If the join | ||
1664 | * succeeds, it will have the negotiated protocol set. | ||
1665 | */ | ||
1666 | dlm->dlm_locking_proto = dlm_protocol; | ||
1667 | dlm->fs_locking_proto = *fs_proto; | ||
1668 | |||
1529 | ret = dlm_join_domain(dlm); | 1669 | ret = dlm_join_domain(dlm); |
1530 | if (ret) { | 1670 | if (ret) { |
1531 | mlog_errno(ret); | 1671 | mlog_errno(ret); |
@@ -1533,6 +1673,9 @@ retry: | |||
1533 | goto leave; | 1673 | goto leave; |
1534 | } | 1674 | } |
1535 | 1675 | ||
1676 | /* Tell the caller what locking protocol we negotiated */ | ||
1677 | *fs_proto = dlm->fs_locking_proto; | ||
1678 | |||
1536 | ret = 0; | 1679 | ret = 0; |
1537 | leave: | 1680 | leave: |
1538 | if (new_ctxt) | 1681 | if (new_ctxt) |
diff --git a/fs/ocfs2/dlm/dlmfs.c b/fs/ocfs2/dlm/dlmfs.c index 6639baab0798..61a000f8524c 100644 --- a/fs/ocfs2/dlm/dlmfs.c +++ b/fs/ocfs2/dlm/dlmfs.c | |||
@@ -60,6 +60,8 @@ | |||
60 | #define MLOG_MASK_PREFIX ML_DLMFS | 60 | #define MLOG_MASK_PREFIX ML_DLMFS |
61 | #include "cluster/masklog.h" | 61 | #include "cluster/masklog.h" |
62 | 62 | ||
63 | #include "ocfs2_lockingver.h" | ||
64 | |||
63 | static const struct super_operations dlmfs_ops; | 65 | static const struct super_operations dlmfs_ops; |
64 | static const struct file_operations dlmfs_file_operations; | 66 | static const struct file_operations dlmfs_file_operations; |
65 | static const struct inode_operations dlmfs_dir_inode_operations; | 67 | static const struct inode_operations dlmfs_dir_inode_operations; |
@@ -70,6 +72,16 @@ static struct kmem_cache *dlmfs_inode_cache; | |||
70 | struct workqueue_struct *user_dlm_worker; | 72 | struct workqueue_struct *user_dlm_worker; |
71 | 73 | ||
72 | /* | 74 | /* |
75 | * This is the userdlmfs locking protocol version. | ||
76 | * | ||
77 | * See fs/ocfs2/dlmglue.c for more details on locking versions. | ||
78 | */ | ||
79 | static const struct dlm_protocol_version user_locking_protocol = { | ||
80 | .pv_major = OCFS2_LOCKING_PROTOCOL_MAJOR, | ||
81 | .pv_minor = OCFS2_LOCKING_PROTOCOL_MINOR, | ||
82 | }; | ||
83 | |||
84 | /* | ||
73 | * decodes a set of open flags into a valid lock level and a set of flags. | 85 | * decodes a set of open flags into a valid lock level and a set of flags. |
74 | * returns < 0 if we have invalid flags | 86 | * returns < 0 if we have invalid flags |
75 | * flags which mean something to us: | 87 | * flags which mean something to us: |
@@ -416,6 +428,7 @@ static int dlmfs_mkdir(struct inode * dir, | |||
416 | struct qstr *domain = &dentry->d_name; | 428 | struct qstr *domain = &dentry->d_name; |
417 | struct dlmfs_inode_private *ip; | 429 | struct dlmfs_inode_private *ip; |
418 | struct dlm_ctxt *dlm; | 430 | struct dlm_ctxt *dlm; |
431 | struct dlm_protocol_version proto = user_locking_protocol; | ||
419 | 432 | ||
420 | mlog(0, "mkdir %.*s\n", domain->len, domain->name); | 433 | mlog(0, "mkdir %.*s\n", domain->len, domain->name); |
421 | 434 | ||
@@ -435,7 +448,7 @@ static int dlmfs_mkdir(struct inode * dir, | |||
435 | 448 | ||
436 | ip = DLMFS_I(inode); | 449 | ip = DLMFS_I(inode); |
437 | 450 | ||
438 | dlm = user_dlm_register_context(domain); | 451 | dlm = user_dlm_register_context(domain, &proto); |
439 | if (IS_ERR(dlm)) { | 452 | if (IS_ERR(dlm)) { |
440 | status = PTR_ERR(dlm); | 453 | status = PTR_ERR(dlm); |
441 | mlog(ML_ERROR, "Error %d could not register domain \"%.*s\"\n", | 454 | mlog(ML_ERROR, "Error %d could not register domain \"%.*s\"\n", |
diff --git a/fs/ocfs2/dlm/userdlm.c b/fs/ocfs2/dlm/userdlm.c index 7d2f578b267d..4cb1d3dae250 100644 --- a/fs/ocfs2/dlm/userdlm.c +++ b/fs/ocfs2/dlm/userdlm.c | |||
@@ -645,7 +645,8 @@ bail: | |||
645 | return status; | 645 | return status; |
646 | } | 646 | } |
647 | 647 | ||
648 | struct dlm_ctxt *user_dlm_register_context(struct qstr *name) | 648 | struct dlm_ctxt *user_dlm_register_context(struct qstr *name, |
649 | struct dlm_protocol_version *proto) | ||
649 | { | 650 | { |
650 | struct dlm_ctxt *dlm; | 651 | struct dlm_ctxt *dlm; |
651 | u32 dlm_key; | 652 | u32 dlm_key; |
@@ -661,7 +662,7 @@ struct dlm_ctxt *user_dlm_register_context(struct qstr *name) | |||
661 | 662 | ||
662 | snprintf(domain, name->len + 1, "%.*s", name->len, name->name); | 663 | snprintf(domain, name->len + 1, "%.*s", name->len, name->name); |
663 | 664 | ||
664 | dlm = dlm_register_domain(domain, dlm_key); | 665 | dlm = dlm_register_domain(domain, dlm_key, proto); |
665 | if (IS_ERR(dlm)) | 666 | if (IS_ERR(dlm)) |
666 | mlog_errno(PTR_ERR(dlm)); | 667 | mlog_errno(PTR_ERR(dlm)); |
667 | 668 | ||
diff --git a/fs/ocfs2/dlm/userdlm.h b/fs/ocfs2/dlm/userdlm.h index c400e93bbf79..39ec27738499 100644 --- a/fs/ocfs2/dlm/userdlm.h +++ b/fs/ocfs2/dlm/userdlm.h | |||
@@ -83,7 +83,8 @@ void user_dlm_write_lvb(struct inode *inode, | |||
83 | void user_dlm_read_lvb(struct inode *inode, | 83 | void user_dlm_read_lvb(struct inode *inode, |
84 | char *val, | 84 | char *val, |
85 | unsigned int len); | 85 | unsigned int len); |
86 | struct dlm_ctxt *user_dlm_register_context(struct qstr *name); | 86 | struct dlm_ctxt *user_dlm_register_context(struct qstr *name, |
87 | struct dlm_protocol_version *proto); | ||
87 | void user_dlm_unregister_context(struct dlm_ctxt *dlm); | 88 | void user_dlm_unregister_context(struct dlm_ctxt *dlm); |
88 | 89 | ||
89 | struct dlmfs_inode_private { | 90 | struct dlmfs_inode_private { |
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c index 3867244fb144..351130c9b734 100644 --- a/fs/ocfs2/dlmglue.c +++ b/fs/ocfs2/dlmglue.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include <cluster/masklog.h> | 43 | #include <cluster/masklog.h> |
44 | 44 | ||
45 | #include "ocfs2.h" | 45 | #include "ocfs2.h" |
46 | #include "ocfs2_lockingver.h" | ||
46 | 47 | ||
47 | #include "alloc.h" | 48 | #include "alloc.h" |
48 | #include "dcache.h" | 49 | #include "dcache.h" |
@@ -258,6 +259,31 @@ static struct ocfs2_lock_res_ops ocfs2_flock_lops = { | |||
258 | .flags = 0, | 259 | .flags = 0, |
259 | }; | 260 | }; |
260 | 261 | ||
262 | /* | ||
263 | * This is the filesystem locking protocol version. | ||
264 | * | ||
265 | * Whenever the filesystem does new things with locks (adds or removes a | ||
266 | * lock, orders them differently, does different things underneath a lock), | ||
267 | * the version must be changed. The protocol is negotiated when joining | ||
268 | * the dlm domain. A node may join the domain if its major version is | ||
269 | * identical to all other nodes and its minor version is greater than | ||
270 | * or equal to all other nodes. When its minor version is greater than | ||
271 | * the other nodes, it will run at the minor version specified by the | ||
272 | * other nodes. | ||
273 | * | ||
274 | * If a locking change is made that will not be compatible with older | ||
275 | * versions, the major number must be increased and the minor version set | ||
276 | * to zero. If a change merely adds a behavior that can be disabled when | ||
277 | * speaking to older versions, the minor version must be increased. If a | ||
278 | * change adds a fully backwards compatible change (eg, LVB changes that | ||
279 | * are just ignored by older versions), the version does not need to be | ||
280 | * updated. | ||
281 | */ | ||
282 | const struct dlm_protocol_version ocfs2_locking_protocol = { | ||
283 | .pv_major = OCFS2_LOCKING_PROTOCOL_MAJOR, | ||
284 | .pv_minor = OCFS2_LOCKING_PROTOCOL_MINOR, | ||
285 | }; | ||
286 | |||
261 | static inline int ocfs2_is_inode_lock(struct ocfs2_lock_res *lockres) | 287 | static inline int ocfs2_is_inode_lock(struct ocfs2_lock_res *lockres) |
262 | { | 288 | { |
263 | return lockres->l_type == OCFS2_LOCK_TYPE_META || | 289 | return lockres->l_type == OCFS2_LOCK_TYPE_META || |
@@ -2506,7 +2532,8 @@ int ocfs2_dlm_init(struct ocfs2_super *osb) | |||
2506 | dlm_key = crc32_le(0, osb->uuid_str, strlen(osb->uuid_str)); | 2532 | dlm_key = crc32_le(0, osb->uuid_str, strlen(osb->uuid_str)); |
2507 | 2533 | ||
2508 | /* for now, uuid == domain */ | 2534 | /* for now, uuid == domain */ |
2509 | dlm = dlm_register_domain(osb->uuid_str, dlm_key); | 2535 | dlm = dlm_register_domain(osb->uuid_str, dlm_key, |
2536 | &osb->osb_locking_proto); | ||
2510 | if (IS_ERR(dlm)) { | 2537 | if (IS_ERR(dlm)) { |
2511 | status = PTR_ERR(dlm); | 2538 | status = PTR_ERR(dlm); |
2512 | mlog_errno(status); | 2539 | mlog_errno(status); |
diff --git a/fs/ocfs2/dlmglue.h b/fs/ocfs2/dlmglue.h index 5f17243ba501..1d5b0699d0a9 100644 --- a/fs/ocfs2/dlmglue.h +++ b/fs/ocfs2/dlmglue.h | |||
@@ -116,4 +116,5 @@ void ocfs2_wake_downconvert_thread(struct ocfs2_super *osb); | |||
116 | struct ocfs2_dlm_debug *ocfs2_new_dlm_debug(void); | 116 | struct ocfs2_dlm_debug *ocfs2_new_dlm_debug(void); |
117 | void ocfs2_put_dlm_debug(struct ocfs2_dlm_debug *dlm_debug); | 117 | void ocfs2_put_dlm_debug(struct ocfs2_dlm_debug *dlm_debug); |
118 | 118 | ||
119 | extern const struct dlm_protocol_version ocfs2_locking_protocol; | ||
119 | #endif /* DLMGLUE_H */ | 120 | #endif /* DLMGLUE_H */ |
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index d08480580470..e8b7292e0152 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h | |||
@@ -251,6 +251,7 @@ struct ocfs2_super | |||
251 | struct ocfs2_lock_res osb_rename_lockres; | 251 | struct ocfs2_lock_res osb_rename_lockres; |
252 | struct dlm_eviction_cb osb_eviction_cb; | 252 | struct dlm_eviction_cb osb_eviction_cb; |
253 | struct ocfs2_dlm_debug *osb_dlm_debug; | 253 | struct ocfs2_dlm_debug *osb_dlm_debug; |
254 | struct dlm_protocol_version osb_locking_proto; | ||
254 | 255 | ||
255 | struct dentry *osb_debug_root; | 256 | struct dentry *osb_debug_root; |
256 | 257 | ||
diff --git a/fs/ocfs2/ocfs2_lockingver.h b/fs/ocfs2/ocfs2_lockingver.h new file mode 100644 index 000000000000..82d5eeac0fff --- /dev/null +++ b/fs/ocfs2/ocfs2_lockingver.h | |||
@@ -0,0 +1,30 @@ | |||
1 | /* -*- mode: c; c-basic-offset: 8; -*- | ||
2 | * vim: noexpandtab sw=8 ts=8 sts=0: | ||
3 | * | ||
4 | * ocfs2_lockingver.h | ||
5 | * | ||
6 | * Defines OCFS2 Locking version values. | ||
7 | * | ||
8 | * Copyright (C) 2008 Oracle. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public | ||
12 | * License, version 2, as published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | */ | ||
19 | |||
20 | #ifndef OCFS2_LOCKINGVER_H | ||
21 | #define OCFS2_LOCKINGVER_H | ||
22 | |||
23 | /* | ||
24 | * The protocol version for ocfs2 cluster locking. See dlmglue.c for | ||
25 | * more details. | ||
26 | */ | ||
27 | #define OCFS2_LOCKING_PROTOCOL_MAJOR 1 | ||
28 | #define OCFS2_LOCKING_PROTOCOL_MINOR 0 | ||
29 | |||
30 | #endif /* OCFS2_LOCKINGVER_H */ | ||
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 01fe40ee5ea9..bec75aff3d9f 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c | |||
@@ -1355,6 +1355,7 @@ static int ocfs2_initialize_super(struct super_block *sb, | |||
1355 | sb->s_fs_info = osb; | 1355 | sb->s_fs_info = osb; |
1356 | sb->s_op = &ocfs2_sops; | 1356 | sb->s_op = &ocfs2_sops; |
1357 | sb->s_export_op = &ocfs2_export_ops; | 1357 | sb->s_export_op = &ocfs2_export_ops; |
1358 | osb->osb_locking_proto = ocfs2_locking_protocol; | ||
1358 | sb->s_time_gran = 1; | 1359 | sb->s_time_gran = 1; |
1359 | sb->s_flags |= MS_NOATIME; | 1360 | sb->s_flags |= MS_NOATIME; |
1360 | /* this is needed to support O_LARGEFILE */ | 1361 | /* this is needed to support O_LARGEFILE */ |