diff options
Diffstat (limited to 'fs/ocfs2')
-rw-r--r-- | fs/ocfs2/acl.c | 3 | ||||
-rw-r--r-- | fs/ocfs2/cluster/heartbeat.c | 532 | ||||
-rw-r--r-- | fs/ocfs2/cluster/heartbeat.h | 4 | ||||
-rw-r--r-- | fs/ocfs2/cluster/masklog.h | 3 | ||||
-rw-r--r-- | fs/ocfs2/cluster/nodemanager.c | 5 | ||||
-rw-r--r-- | fs/ocfs2/cluster/ocfs2_nodemanager.h | 6 | ||||
-rw-r--r-- | fs/ocfs2/cluster/tcp.c | 7 | ||||
-rw-r--r-- | fs/ocfs2/dir.c | 24 | ||||
-rw-r--r-- | fs/ocfs2/dlm/dlmcommon.h | 30 | ||||
-rw-r--r-- | fs/ocfs2/dlm/dlmdebug.c | 13 | ||||
-rw-r--r-- | fs/ocfs2/dlm/dlmdomain.c | 401 | ||||
-rw-r--r-- | fs/ocfs2/dlm/dlmmaster.c | 40 | ||||
-rw-r--r-- | fs/ocfs2/dlmglue.h | 1 | ||||
-rw-r--r-- | fs/ocfs2/ocfs2.h | 40 | ||||
-rw-r--r-- | fs/ocfs2/ocfs2_fs.h | 78 | ||||
-rw-r--r-- | fs/ocfs2/ocfs2_ioctl.h | 8 | ||||
-rw-r--r-- | fs/ocfs2/refcounttree.c | 5 | ||||
-rw-r--r-- | fs/ocfs2/reservations.c | 22 | ||||
-rw-r--r-- | fs/ocfs2/stack_o2cb.c | 2 | ||||
-rw-r--r-- | fs/ocfs2/suballoc.c | 4 | ||||
-rw-r--r-- | fs/ocfs2/super.c | 59 | ||||
-rw-r--r-- | fs/ocfs2/symlink.c | 2 | ||||
-rw-r--r-- | fs/ocfs2/xattr.c | 4 |
23 files changed, 1186 insertions, 107 deletions
diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c index a76e0aa5cd3f..391915093fe1 100644 --- a/fs/ocfs2/acl.c +++ b/fs/ocfs2/acl.c | |||
@@ -209,7 +209,10 @@ static int ocfs2_acl_set_mode(struct inode *inode, struct buffer_head *di_bh, | |||
209 | } | 209 | } |
210 | 210 | ||
211 | inode->i_mode = new_mode; | 211 | inode->i_mode = new_mode; |
212 | inode->i_ctime = CURRENT_TIME; | ||
212 | di->i_mode = cpu_to_le16(inode->i_mode); | 213 | di->i_mode = cpu_to_le16(inode->i_mode); |
214 | di->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec); | ||
215 | di->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec); | ||
213 | 216 | ||
214 | ocfs2_journal_dirty(handle, di_bh); | 217 | ocfs2_journal_dirty(handle, di_bh); |
215 | 218 | ||
diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 41d5f1f92d56..52c7557f3e25 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c | |||
@@ -62,10 +62,51 @@ static unsigned long o2hb_live_node_bitmap[BITS_TO_LONGS(O2NM_MAX_NODES)]; | |||
62 | static LIST_HEAD(o2hb_node_events); | 62 | static LIST_HEAD(o2hb_node_events); |
63 | static DECLARE_WAIT_QUEUE_HEAD(o2hb_steady_queue); | 63 | static DECLARE_WAIT_QUEUE_HEAD(o2hb_steady_queue); |
64 | 64 | ||
65 | /* | ||
66 | * In global heartbeat, we maintain a series of region bitmaps. | ||
67 | * - o2hb_region_bitmap allows us to limit the region number to max region. | ||
68 | * - o2hb_live_region_bitmap tracks live regions (seen steady iterations). | ||
69 | * - o2hb_quorum_region_bitmap tracks live regions that have seen all nodes | ||
70 | * heartbeat on it. | ||
71 | * - o2hb_failed_region_bitmap tracks the regions that have seen io timeouts. | ||
72 | */ | ||
73 | static unsigned long o2hb_region_bitmap[BITS_TO_LONGS(O2NM_MAX_REGIONS)]; | ||
74 | static unsigned long o2hb_live_region_bitmap[BITS_TO_LONGS(O2NM_MAX_REGIONS)]; | ||
75 | static unsigned long o2hb_quorum_region_bitmap[BITS_TO_LONGS(O2NM_MAX_REGIONS)]; | ||
76 | static unsigned long o2hb_failed_region_bitmap[BITS_TO_LONGS(O2NM_MAX_REGIONS)]; | ||
77 | |||
78 | #define O2HB_DB_TYPE_LIVENODES 0 | ||
79 | #define O2HB_DB_TYPE_LIVEREGIONS 1 | ||
80 | #define O2HB_DB_TYPE_QUORUMREGIONS 2 | ||
81 | #define O2HB_DB_TYPE_FAILEDREGIONS 3 | ||
82 | #define O2HB_DB_TYPE_REGION_LIVENODES 4 | ||
83 | #define O2HB_DB_TYPE_REGION_NUMBER 5 | ||
84 | #define O2HB_DB_TYPE_REGION_ELAPSED_TIME 6 | ||
85 | struct o2hb_debug_buf { | ||
86 | int db_type; | ||
87 | int db_size; | ||
88 | int db_len; | ||
89 | void *db_data; | ||
90 | }; | ||
91 | |||
92 | static struct o2hb_debug_buf *o2hb_db_livenodes; | ||
93 | static struct o2hb_debug_buf *o2hb_db_liveregions; | ||
94 | static struct o2hb_debug_buf *o2hb_db_quorumregions; | ||
95 | static struct o2hb_debug_buf *o2hb_db_failedregions; | ||
96 | |||
65 | #define O2HB_DEBUG_DIR "o2hb" | 97 | #define O2HB_DEBUG_DIR "o2hb" |
66 | #define O2HB_DEBUG_LIVENODES "livenodes" | 98 | #define O2HB_DEBUG_LIVENODES "livenodes" |
99 | #define O2HB_DEBUG_LIVEREGIONS "live_regions" | ||
100 | #define O2HB_DEBUG_QUORUMREGIONS "quorum_regions" | ||
101 | #define O2HB_DEBUG_FAILEDREGIONS "failed_regions" | ||
102 | #define O2HB_DEBUG_REGION_NUMBER "num" | ||
103 | #define O2HB_DEBUG_REGION_ELAPSED_TIME "elapsed_time_in_ms" | ||
104 | |||
67 | static struct dentry *o2hb_debug_dir; | 105 | static struct dentry *o2hb_debug_dir; |
68 | static struct dentry *o2hb_debug_livenodes; | 106 | static struct dentry *o2hb_debug_livenodes; |
107 | static struct dentry *o2hb_debug_liveregions; | ||
108 | static struct dentry *o2hb_debug_quorumregions; | ||
109 | static struct dentry *o2hb_debug_failedregions; | ||
69 | 110 | ||
70 | static LIST_HEAD(o2hb_all_regions); | 111 | static LIST_HEAD(o2hb_all_regions); |
71 | 112 | ||
@@ -77,7 +118,19 @@ static struct o2hb_callback *hbcall_from_type(enum o2hb_callback_type type); | |||
77 | 118 | ||
78 | #define O2HB_DEFAULT_BLOCK_BITS 9 | 119 | #define O2HB_DEFAULT_BLOCK_BITS 9 |
79 | 120 | ||
121 | enum o2hb_heartbeat_modes { | ||
122 | O2HB_HEARTBEAT_LOCAL = 0, | ||
123 | O2HB_HEARTBEAT_GLOBAL, | ||
124 | O2HB_HEARTBEAT_NUM_MODES, | ||
125 | }; | ||
126 | |||
127 | char *o2hb_heartbeat_mode_desc[O2HB_HEARTBEAT_NUM_MODES] = { | ||
128 | "local", /* O2HB_HEARTBEAT_LOCAL */ | ||
129 | "global", /* O2HB_HEARTBEAT_GLOBAL */ | ||
130 | }; | ||
131 | |||
80 | unsigned int o2hb_dead_threshold = O2HB_DEFAULT_DEAD_THRESHOLD; | 132 | unsigned int o2hb_dead_threshold = O2HB_DEFAULT_DEAD_THRESHOLD; |
133 | unsigned int o2hb_heartbeat_mode = O2HB_HEARTBEAT_LOCAL; | ||
81 | 134 | ||
82 | /* Only sets a new threshold if there are no active regions. | 135 | /* Only sets a new threshold if there are no active regions. |
83 | * | 136 | * |
@@ -94,6 +147,22 @@ static void o2hb_dead_threshold_set(unsigned int threshold) | |||
94 | } | 147 | } |
95 | } | 148 | } |
96 | 149 | ||
150 | static int o2hb_global_hearbeat_mode_set(unsigned int hb_mode) | ||
151 | { | ||
152 | int ret = -1; | ||
153 | |||
154 | if (hb_mode < O2HB_HEARTBEAT_NUM_MODES) { | ||
155 | spin_lock(&o2hb_live_lock); | ||
156 | if (list_empty(&o2hb_all_regions)) { | ||
157 | o2hb_heartbeat_mode = hb_mode; | ||
158 | ret = 0; | ||
159 | } | ||
160 | spin_unlock(&o2hb_live_lock); | ||
161 | } | ||
162 | |||
163 | return ret; | ||
164 | } | ||
165 | |||
97 | struct o2hb_node_event { | 166 | struct o2hb_node_event { |
98 | struct list_head hn_item; | 167 | struct list_head hn_item; |
99 | enum o2hb_callback_type hn_event_type; | 168 | enum o2hb_callback_type hn_event_type; |
@@ -135,6 +204,18 @@ struct o2hb_region { | |||
135 | struct block_device *hr_bdev; | 204 | struct block_device *hr_bdev; |
136 | struct o2hb_disk_slot *hr_slots; | 205 | struct o2hb_disk_slot *hr_slots; |
137 | 206 | ||
207 | /* live node map of this region */ | ||
208 | unsigned long hr_live_node_bitmap[BITS_TO_LONGS(O2NM_MAX_NODES)]; | ||
209 | unsigned int hr_region_num; | ||
210 | |||
211 | struct dentry *hr_debug_dir; | ||
212 | struct dentry *hr_debug_livenodes; | ||
213 | struct dentry *hr_debug_regnum; | ||
214 | struct dentry *hr_debug_elapsed_time; | ||
215 | struct o2hb_debug_buf *hr_db_livenodes; | ||
216 | struct o2hb_debug_buf *hr_db_regnum; | ||
217 | struct o2hb_debug_buf *hr_db_elapsed_time; | ||
218 | |||
138 | /* let the person setting up hb wait for it to return until it | 219 | /* let the person setting up hb wait for it to return until it |
139 | * has reached a 'steady' state. This will be fixed when we have | 220 | * has reached a 'steady' state. This will be fixed when we have |
140 | * a more complete api that doesn't lead to this sort of fragility. */ | 221 | * a more complete api that doesn't lead to this sort of fragility. */ |
@@ -163,8 +244,19 @@ struct o2hb_bio_wait_ctxt { | |||
163 | int wc_error; | 244 | int wc_error; |
164 | }; | 245 | }; |
165 | 246 | ||
247 | static int o2hb_pop_count(void *map, int count) | ||
248 | { | ||
249 | int i = -1, pop = 0; | ||
250 | |||
251 | while ((i = find_next_bit(map, count, i + 1)) < count) | ||
252 | pop++; | ||
253 | return pop; | ||
254 | } | ||
255 | |||
166 | static void o2hb_write_timeout(struct work_struct *work) | 256 | static void o2hb_write_timeout(struct work_struct *work) |
167 | { | 257 | { |
258 | int failed, quorum; | ||
259 | unsigned long flags; | ||
168 | struct o2hb_region *reg = | 260 | struct o2hb_region *reg = |
169 | container_of(work, struct o2hb_region, | 261 | container_of(work, struct o2hb_region, |
170 | hr_write_timeout_work.work); | 262 | hr_write_timeout_work.work); |
@@ -172,6 +264,28 @@ static void o2hb_write_timeout(struct work_struct *work) | |||
172 | mlog(ML_ERROR, "Heartbeat write timeout to device %s after %u " | 264 | mlog(ML_ERROR, "Heartbeat write timeout to device %s after %u " |
173 | "milliseconds\n", reg->hr_dev_name, | 265 | "milliseconds\n", reg->hr_dev_name, |
174 | jiffies_to_msecs(jiffies - reg->hr_last_timeout_start)); | 266 | jiffies_to_msecs(jiffies - reg->hr_last_timeout_start)); |
267 | |||
268 | if (o2hb_global_heartbeat_active()) { | ||
269 | spin_lock_irqsave(&o2hb_live_lock, flags); | ||
270 | if (test_bit(reg->hr_region_num, o2hb_quorum_region_bitmap)) | ||
271 | set_bit(reg->hr_region_num, o2hb_failed_region_bitmap); | ||
272 | failed = o2hb_pop_count(&o2hb_failed_region_bitmap, | ||
273 | O2NM_MAX_REGIONS); | ||
274 | quorum = o2hb_pop_count(&o2hb_quorum_region_bitmap, | ||
275 | O2NM_MAX_REGIONS); | ||
276 | spin_unlock_irqrestore(&o2hb_live_lock, flags); | ||
277 | |||
278 | mlog(ML_HEARTBEAT, "Number of regions %d, failed regions %d\n", | ||
279 | quorum, failed); | ||
280 | |||
281 | /* | ||
282 | * Fence if the number of failed regions >= half the number | ||
283 | * of quorum regions | ||
284 | */ | ||
285 | if ((failed << 1) < quorum) | ||
286 | return; | ||
287 | } | ||
288 | |||
175 | o2quo_disk_timeout(); | 289 | o2quo_disk_timeout(); |
176 | } | 290 | } |
177 | 291 | ||
@@ -180,6 +294,11 @@ static void o2hb_arm_write_timeout(struct o2hb_region *reg) | |||
180 | mlog(ML_HEARTBEAT, "Queue write timeout for %u ms\n", | 294 | mlog(ML_HEARTBEAT, "Queue write timeout for %u ms\n", |
181 | O2HB_MAX_WRITE_TIMEOUT_MS); | 295 | O2HB_MAX_WRITE_TIMEOUT_MS); |
182 | 296 | ||
297 | if (o2hb_global_heartbeat_active()) { | ||
298 | spin_lock(&o2hb_live_lock); | ||
299 | clear_bit(reg->hr_region_num, o2hb_failed_region_bitmap); | ||
300 | spin_unlock(&o2hb_live_lock); | ||
301 | } | ||
183 | cancel_delayed_work(®->hr_write_timeout_work); | 302 | cancel_delayed_work(®->hr_write_timeout_work); |
184 | reg->hr_last_timeout_start = jiffies; | 303 | reg->hr_last_timeout_start = jiffies; |
185 | schedule_delayed_work(®->hr_write_timeout_work, | 304 | schedule_delayed_work(®->hr_write_timeout_work, |
@@ -513,6 +632,8 @@ static void o2hb_queue_node_event(struct o2hb_node_event *event, | |||
513 | { | 632 | { |
514 | assert_spin_locked(&o2hb_live_lock); | 633 | assert_spin_locked(&o2hb_live_lock); |
515 | 634 | ||
635 | BUG_ON((!node) && (type != O2HB_NODE_DOWN_CB)); | ||
636 | |||
516 | event->hn_event_type = type; | 637 | event->hn_event_type = type; |
517 | event->hn_node = node; | 638 | event->hn_node = node; |
518 | event->hn_node_num = node_num; | 639 | event->hn_node_num = node_num; |
@@ -554,6 +675,35 @@ static void o2hb_shutdown_slot(struct o2hb_disk_slot *slot) | |||
554 | o2nm_node_put(node); | 675 | o2nm_node_put(node); |
555 | } | 676 | } |
556 | 677 | ||
678 | static void o2hb_set_quorum_device(struct o2hb_region *reg, | ||
679 | struct o2hb_disk_slot *slot) | ||
680 | { | ||
681 | assert_spin_locked(&o2hb_live_lock); | ||
682 | |||
683 | if (!o2hb_global_heartbeat_active()) | ||
684 | return; | ||
685 | |||
686 | if (test_bit(reg->hr_region_num, o2hb_quorum_region_bitmap)) | ||
687 | return; | ||
688 | |||
689 | /* | ||
690 | * A region can be added to the quorum only when it sees all | ||
691 | * live nodes heartbeat on it. In other words, the region has been | ||
692 | * added to all nodes. | ||
693 | */ | ||
694 | if (memcmp(reg->hr_live_node_bitmap, o2hb_live_node_bitmap, | ||
695 | sizeof(o2hb_live_node_bitmap))) | ||
696 | return; | ||
697 | |||
698 | if (slot->ds_changed_samples < O2HB_LIVE_THRESHOLD) | ||
699 | return; | ||
700 | |||
701 | printk(KERN_NOTICE "o2hb: Region %s is now a quorum device\n", | ||
702 | config_item_name(®->hr_item)); | ||
703 | |||
704 | set_bit(reg->hr_region_num, o2hb_quorum_region_bitmap); | ||
705 | } | ||
706 | |||
557 | static int o2hb_check_slot(struct o2hb_region *reg, | 707 | static int o2hb_check_slot(struct o2hb_region *reg, |
558 | struct o2hb_disk_slot *slot) | 708 | struct o2hb_disk_slot *slot) |
559 | { | 709 | { |
@@ -565,14 +715,22 @@ static int o2hb_check_slot(struct o2hb_region *reg, | |||
565 | u64 cputime; | 715 | u64 cputime; |
566 | unsigned int dead_ms = o2hb_dead_threshold * O2HB_REGION_TIMEOUT_MS; | 716 | unsigned int dead_ms = o2hb_dead_threshold * O2HB_REGION_TIMEOUT_MS; |
567 | unsigned int slot_dead_ms; | 717 | unsigned int slot_dead_ms; |
718 | int tmp; | ||
568 | 719 | ||
569 | memcpy(hb_block, slot->ds_raw_block, reg->hr_block_bytes); | 720 | memcpy(hb_block, slot->ds_raw_block, reg->hr_block_bytes); |
570 | 721 | ||
571 | /* Is this correct? Do we assume that the node doesn't exist | 722 | /* |
572 | * if we're not configured for him? */ | 723 | * If a node is no longer configured but is still in the livemap, we |
724 | * may need to clear that bit from the livemap. | ||
725 | */ | ||
573 | node = o2nm_get_node_by_num(slot->ds_node_num); | 726 | node = o2nm_get_node_by_num(slot->ds_node_num); |
574 | if (!node) | 727 | if (!node) { |
575 | return 0; | 728 | spin_lock(&o2hb_live_lock); |
729 | tmp = test_bit(slot->ds_node_num, o2hb_live_node_bitmap); | ||
730 | spin_unlock(&o2hb_live_lock); | ||
731 | if (!tmp) | ||
732 | return 0; | ||
733 | } | ||
576 | 734 | ||
577 | if (!o2hb_verify_crc(reg, hb_block)) { | 735 | if (!o2hb_verify_crc(reg, hb_block)) { |
578 | /* all paths from here will drop o2hb_live_lock for | 736 | /* all paths from here will drop o2hb_live_lock for |
@@ -639,8 +797,12 @@ fire_callbacks: | |||
639 | mlog(ML_HEARTBEAT, "Node %d (id 0x%llx) joined my region\n", | 797 | mlog(ML_HEARTBEAT, "Node %d (id 0x%llx) joined my region\n", |
640 | slot->ds_node_num, (long long)slot->ds_last_generation); | 798 | slot->ds_node_num, (long long)slot->ds_last_generation); |
641 | 799 | ||
800 | set_bit(slot->ds_node_num, reg->hr_live_node_bitmap); | ||
801 | |||
642 | /* first on the list generates a callback */ | 802 | /* first on the list generates a callback */ |
643 | if (list_empty(&o2hb_live_slots[slot->ds_node_num])) { | 803 | if (list_empty(&o2hb_live_slots[slot->ds_node_num])) { |
804 | mlog(ML_HEARTBEAT, "o2hb: Add node %d to live nodes " | ||
805 | "bitmap\n", slot->ds_node_num); | ||
644 | set_bit(slot->ds_node_num, o2hb_live_node_bitmap); | 806 | set_bit(slot->ds_node_num, o2hb_live_node_bitmap); |
645 | 807 | ||
646 | o2hb_queue_node_event(&event, O2HB_NODE_UP_CB, node, | 808 | o2hb_queue_node_event(&event, O2HB_NODE_UP_CB, node, |
@@ -684,13 +846,18 @@ fire_callbacks: | |||
684 | mlog(ML_HEARTBEAT, "Node %d left my region\n", | 846 | mlog(ML_HEARTBEAT, "Node %d left my region\n", |
685 | slot->ds_node_num); | 847 | slot->ds_node_num); |
686 | 848 | ||
849 | clear_bit(slot->ds_node_num, reg->hr_live_node_bitmap); | ||
850 | |||
687 | /* last off the live_slot generates a callback */ | 851 | /* last off the live_slot generates a callback */ |
688 | list_del_init(&slot->ds_live_item); | 852 | list_del_init(&slot->ds_live_item); |
689 | if (list_empty(&o2hb_live_slots[slot->ds_node_num])) { | 853 | if (list_empty(&o2hb_live_slots[slot->ds_node_num])) { |
854 | mlog(ML_HEARTBEAT, "o2hb: Remove node %d from live " | ||
855 | "nodes bitmap\n", slot->ds_node_num); | ||
690 | clear_bit(slot->ds_node_num, o2hb_live_node_bitmap); | 856 | clear_bit(slot->ds_node_num, o2hb_live_node_bitmap); |
691 | 857 | ||
692 | o2hb_queue_node_event(&event, O2HB_NODE_DOWN_CB, node, | 858 | /* node can be null */ |
693 | slot->ds_node_num); | 859 | o2hb_queue_node_event(&event, O2HB_NODE_DOWN_CB, |
860 | node, slot->ds_node_num); | ||
694 | 861 | ||
695 | changed = 1; | 862 | changed = 1; |
696 | } | 863 | } |
@@ -706,11 +873,14 @@ fire_callbacks: | |||
706 | slot->ds_equal_samples = 0; | 873 | slot->ds_equal_samples = 0; |
707 | } | 874 | } |
708 | out: | 875 | out: |
876 | o2hb_set_quorum_device(reg, slot); | ||
877 | |||
709 | spin_unlock(&o2hb_live_lock); | 878 | spin_unlock(&o2hb_live_lock); |
710 | 879 | ||
711 | o2hb_run_event_list(&event); | 880 | o2hb_run_event_list(&event); |
712 | 881 | ||
713 | o2nm_node_put(node); | 882 | if (node) |
883 | o2nm_node_put(node); | ||
714 | return changed; | 884 | return changed; |
715 | } | 885 | } |
716 | 886 | ||
@@ -737,6 +907,7 @@ static int o2hb_do_disk_heartbeat(struct o2hb_region *reg) | |||
737 | { | 907 | { |
738 | int i, ret, highest_node, change = 0; | 908 | int i, ret, highest_node, change = 0; |
739 | unsigned long configured_nodes[BITS_TO_LONGS(O2NM_MAX_NODES)]; | 909 | unsigned long configured_nodes[BITS_TO_LONGS(O2NM_MAX_NODES)]; |
910 | unsigned long live_node_bitmap[BITS_TO_LONGS(O2NM_MAX_NODES)]; | ||
740 | struct o2hb_bio_wait_ctxt write_wc; | 911 | struct o2hb_bio_wait_ctxt write_wc; |
741 | 912 | ||
742 | ret = o2nm_configured_node_map(configured_nodes, | 913 | ret = o2nm_configured_node_map(configured_nodes, |
@@ -746,6 +917,17 @@ static int o2hb_do_disk_heartbeat(struct o2hb_region *reg) | |||
746 | return ret; | 917 | return ret; |
747 | } | 918 | } |
748 | 919 | ||
920 | /* | ||
921 | * If a node is not configured but is in the livemap, we still need | ||
922 | * to read the slot so as to be able to remove it from the livemap. | ||
923 | */ | ||
924 | o2hb_fill_node_map(live_node_bitmap, sizeof(live_node_bitmap)); | ||
925 | i = -1; | ||
926 | while ((i = find_next_bit(live_node_bitmap, | ||
927 | O2NM_MAX_NODES, i + 1)) < O2NM_MAX_NODES) { | ||
928 | set_bit(i, configured_nodes); | ||
929 | } | ||
930 | |||
749 | highest_node = o2hb_highest_node(configured_nodes, O2NM_MAX_NODES); | 931 | highest_node = o2hb_highest_node(configured_nodes, O2NM_MAX_NODES); |
750 | if (highest_node >= O2NM_MAX_NODES) { | 932 | if (highest_node >= O2NM_MAX_NODES) { |
751 | mlog(ML_NOTICE, "ocfs2_heartbeat: no configured nodes found!\n"); | 933 | mlog(ML_NOTICE, "ocfs2_heartbeat: no configured nodes found!\n"); |
@@ -917,21 +1099,59 @@ static int o2hb_thread(void *data) | |||
917 | #ifdef CONFIG_DEBUG_FS | 1099 | #ifdef CONFIG_DEBUG_FS |
918 | static int o2hb_debug_open(struct inode *inode, struct file *file) | 1100 | static int o2hb_debug_open(struct inode *inode, struct file *file) |
919 | { | 1101 | { |
1102 | struct o2hb_debug_buf *db = inode->i_private; | ||
1103 | struct o2hb_region *reg; | ||
920 | unsigned long map[BITS_TO_LONGS(O2NM_MAX_NODES)]; | 1104 | unsigned long map[BITS_TO_LONGS(O2NM_MAX_NODES)]; |
921 | char *buf = NULL; | 1105 | char *buf = NULL; |
922 | int i = -1; | 1106 | int i = -1; |
923 | int out = 0; | 1107 | int out = 0; |
924 | 1108 | ||
1109 | /* max_nodes should be the largest bitmap we pass here */ | ||
1110 | BUG_ON(sizeof(map) < db->db_size); | ||
1111 | |||
925 | buf = kmalloc(PAGE_SIZE, GFP_KERNEL); | 1112 | buf = kmalloc(PAGE_SIZE, GFP_KERNEL); |
926 | if (!buf) | 1113 | if (!buf) |
927 | goto bail; | 1114 | goto bail; |
928 | 1115 | ||
929 | o2hb_fill_node_map(map, sizeof(map)); | 1116 | switch (db->db_type) { |
1117 | case O2HB_DB_TYPE_LIVENODES: | ||
1118 | case O2HB_DB_TYPE_LIVEREGIONS: | ||
1119 | case O2HB_DB_TYPE_QUORUMREGIONS: | ||
1120 | case O2HB_DB_TYPE_FAILEDREGIONS: | ||
1121 | spin_lock(&o2hb_live_lock); | ||
1122 | memcpy(map, db->db_data, db->db_size); | ||
1123 | spin_unlock(&o2hb_live_lock); | ||
1124 | break; | ||
1125 | |||
1126 | case O2HB_DB_TYPE_REGION_LIVENODES: | ||
1127 | spin_lock(&o2hb_live_lock); | ||
1128 | reg = (struct o2hb_region *)db->db_data; | ||
1129 | memcpy(map, reg->hr_live_node_bitmap, db->db_size); | ||
1130 | spin_unlock(&o2hb_live_lock); | ||
1131 | break; | ||
1132 | |||
1133 | case O2HB_DB_TYPE_REGION_NUMBER: | ||
1134 | reg = (struct o2hb_region *)db->db_data; | ||
1135 | out += snprintf(buf + out, PAGE_SIZE - out, "%d\n", | ||
1136 | reg->hr_region_num); | ||
1137 | goto done; | ||
1138 | |||
1139 | case O2HB_DB_TYPE_REGION_ELAPSED_TIME: | ||
1140 | reg = (struct o2hb_region *)db->db_data; | ||
1141 | out += snprintf(buf + out, PAGE_SIZE - out, "%u\n", | ||
1142 | jiffies_to_msecs(jiffies - | ||
1143 | reg->hr_last_timeout_start)); | ||
1144 | goto done; | ||
1145 | |||
1146 | default: | ||
1147 | goto done; | ||
1148 | } | ||
930 | 1149 | ||
931 | while ((i = find_next_bit(map, O2NM_MAX_NODES, i + 1)) < O2NM_MAX_NODES) | 1150 | while ((i = find_next_bit(map, db->db_len, i + 1)) < db->db_len) |
932 | out += snprintf(buf + out, PAGE_SIZE - out, "%d ", i); | 1151 | out += snprintf(buf + out, PAGE_SIZE - out, "%d ", i); |
933 | out += snprintf(buf + out, PAGE_SIZE - out, "\n"); | 1152 | out += snprintf(buf + out, PAGE_SIZE - out, "\n"); |
934 | 1153 | ||
1154 | done: | ||
935 | i_size_write(inode, out); | 1155 | i_size_write(inode, out); |
936 | 1156 | ||
937 | file->private_data = buf; | 1157 | file->private_data = buf; |
@@ -978,10 +1198,104 @@ static const struct file_operations o2hb_debug_fops = { | |||
978 | 1198 | ||
979 | void o2hb_exit(void) | 1199 | void o2hb_exit(void) |
980 | { | 1200 | { |
981 | if (o2hb_debug_livenodes) | 1201 | kfree(o2hb_db_livenodes); |
982 | debugfs_remove(o2hb_debug_livenodes); | 1202 | kfree(o2hb_db_liveregions); |
983 | if (o2hb_debug_dir) | 1203 | kfree(o2hb_db_quorumregions); |
984 | debugfs_remove(o2hb_debug_dir); | 1204 | kfree(o2hb_db_failedregions); |
1205 | debugfs_remove(o2hb_debug_failedregions); | ||
1206 | debugfs_remove(o2hb_debug_quorumregions); | ||
1207 | debugfs_remove(o2hb_debug_liveregions); | ||
1208 | debugfs_remove(o2hb_debug_livenodes); | ||
1209 | debugfs_remove(o2hb_debug_dir); | ||
1210 | } | ||
1211 | |||
1212 | static struct dentry *o2hb_debug_create(const char *name, struct dentry *dir, | ||
1213 | struct o2hb_debug_buf **db, int db_len, | ||
1214 | int type, int size, int len, void *data) | ||
1215 | { | ||
1216 | *db = kmalloc(db_len, GFP_KERNEL); | ||
1217 | if (!*db) | ||
1218 | return NULL; | ||
1219 | |||
1220 | (*db)->db_type = type; | ||
1221 | (*db)->db_size = size; | ||
1222 | (*db)->db_len = len; | ||
1223 | (*db)->db_data = data; | ||
1224 | |||
1225 | return debugfs_create_file(name, S_IFREG|S_IRUSR, dir, *db, | ||
1226 | &o2hb_debug_fops); | ||
1227 | } | ||
1228 | |||
1229 | static int o2hb_debug_init(void) | ||
1230 | { | ||
1231 | int ret = -ENOMEM; | ||
1232 | |||
1233 | o2hb_debug_dir = debugfs_create_dir(O2HB_DEBUG_DIR, NULL); | ||
1234 | if (!o2hb_debug_dir) { | ||
1235 | mlog_errno(ret); | ||
1236 | goto bail; | ||
1237 | } | ||
1238 | |||
1239 | o2hb_debug_livenodes = o2hb_debug_create(O2HB_DEBUG_LIVENODES, | ||
1240 | o2hb_debug_dir, | ||
1241 | &o2hb_db_livenodes, | ||
1242 | sizeof(*o2hb_db_livenodes), | ||
1243 | O2HB_DB_TYPE_LIVENODES, | ||
1244 | sizeof(o2hb_live_node_bitmap), | ||
1245 | O2NM_MAX_NODES, | ||
1246 | o2hb_live_node_bitmap); | ||
1247 | if (!o2hb_debug_livenodes) { | ||
1248 | mlog_errno(ret); | ||
1249 | goto bail; | ||
1250 | } | ||
1251 | |||
1252 | o2hb_debug_liveregions = o2hb_debug_create(O2HB_DEBUG_LIVEREGIONS, | ||
1253 | o2hb_debug_dir, | ||
1254 | &o2hb_db_liveregions, | ||
1255 | sizeof(*o2hb_db_liveregions), | ||
1256 | O2HB_DB_TYPE_LIVEREGIONS, | ||
1257 | sizeof(o2hb_live_region_bitmap), | ||
1258 | O2NM_MAX_REGIONS, | ||
1259 | o2hb_live_region_bitmap); | ||
1260 | if (!o2hb_debug_liveregions) { | ||
1261 | mlog_errno(ret); | ||
1262 | goto bail; | ||
1263 | } | ||
1264 | |||
1265 | o2hb_debug_quorumregions = | ||
1266 | o2hb_debug_create(O2HB_DEBUG_QUORUMREGIONS, | ||
1267 | o2hb_debug_dir, | ||
1268 | &o2hb_db_quorumregions, | ||
1269 | sizeof(*o2hb_db_quorumregions), | ||
1270 | O2HB_DB_TYPE_QUORUMREGIONS, | ||
1271 | sizeof(o2hb_quorum_region_bitmap), | ||
1272 | O2NM_MAX_REGIONS, | ||
1273 | o2hb_quorum_region_bitmap); | ||
1274 | if (!o2hb_debug_quorumregions) { | ||
1275 | mlog_errno(ret); | ||
1276 | goto bail; | ||
1277 | } | ||
1278 | |||
1279 | o2hb_debug_failedregions = | ||
1280 | o2hb_debug_create(O2HB_DEBUG_FAILEDREGIONS, | ||
1281 | o2hb_debug_dir, | ||
1282 | &o2hb_db_failedregions, | ||
1283 | sizeof(*o2hb_db_failedregions), | ||
1284 | O2HB_DB_TYPE_FAILEDREGIONS, | ||
1285 | sizeof(o2hb_failed_region_bitmap), | ||
1286 | O2NM_MAX_REGIONS, | ||
1287 | o2hb_failed_region_bitmap); | ||
1288 | if (!o2hb_debug_failedregions) { | ||
1289 | mlog_errno(ret); | ||
1290 | goto bail; | ||
1291 | } | ||
1292 | |||
1293 | ret = 0; | ||
1294 | bail: | ||
1295 | if (ret) | ||
1296 | o2hb_exit(); | ||
1297 | |||
1298 | return ret; | ||
985 | } | 1299 | } |
986 | 1300 | ||
987 | int o2hb_init(void) | 1301 | int o2hb_init(void) |
@@ -997,24 +1311,12 @@ int o2hb_init(void) | |||
997 | INIT_LIST_HEAD(&o2hb_node_events); | 1311 | INIT_LIST_HEAD(&o2hb_node_events); |
998 | 1312 | ||
999 | memset(o2hb_live_node_bitmap, 0, sizeof(o2hb_live_node_bitmap)); | 1313 | memset(o2hb_live_node_bitmap, 0, sizeof(o2hb_live_node_bitmap)); |
1314 | memset(o2hb_region_bitmap, 0, sizeof(o2hb_region_bitmap)); | ||
1315 | memset(o2hb_live_region_bitmap, 0, sizeof(o2hb_live_region_bitmap)); | ||
1316 | memset(o2hb_quorum_region_bitmap, 0, sizeof(o2hb_quorum_region_bitmap)); | ||
1317 | memset(o2hb_failed_region_bitmap, 0, sizeof(o2hb_failed_region_bitmap)); | ||
1000 | 1318 | ||
1001 | o2hb_debug_dir = debugfs_create_dir(O2HB_DEBUG_DIR, NULL); | 1319 | return o2hb_debug_init(); |
1002 | if (!o2hb_debug_dir) { | ||
1003 | mlog_errno(-ENOMEM); | ||
1004 | return -ENOMEM; | ||
1005 | } | ||
1006 | |||
1007 | o2hb_debug_livenodes = debugfs_create_file(O2HB_DEBUG_LIVENODES, | ||
1008 | S_IFREG|S_IRUSR, | ||
1009 | o2hb_debug_dir, NULL, | ||
1010 | &o2hb_debug_fops); | ||
1011 | if (!o2hb_debug_livenodes) { | ||
1012 | mlog_errno(-ENOMEM); | ||
1013 | debugfs_remove(o2hb_debug_dir); | ||
1014 | return -ENOMEM; | ||
1015 | } | ||
1016 | |||
1017 | return 0; | ||
1018 | } | 1320 | } |
1019 | 1321 | ||
1020 | /* if we're already in a callback then we're already serialized by the sem */ | 1322 | /* if we're already in a callback then we're already serialized by the sem */ |
@@ -1078,6 +1380,13 @@ static void o2hb_region_release(struct config_item *item) | |||
1078 | if (reg->hr_slots) | 1380 | if (reg->hr_slots) |
1079 | kfree(reg->hr_slots); | 1381 | kfree(reg->hr_slots); |
1080 | 1382 | ||
1383 | kfree(reg->hr_db_regnum); | ||
1384 | kfree(reg->hr_db_livenodes); | ||
1385 | debugfs_remove(reg->hr_debug_livenodes); | ||
1386 | debugfs_remove(reg->hr_debug_regnum); | ||
1387 | debugfs_remove(reg->hr_debug_elapsed_time); | ||
1388 | debugfs_remove(reg->hr_debug_dir); | ||
1389 | |||
1081 | spin_lock(&o2hb_live_lock); | 1390 | spin_lock(&o2hb_live_lock); |
1082 | list_del(®->hr_all_item); | 1391 | list_del(®->hr_all_item); |
1083 | spin_unlock(&o2hb_live_lock); | 1392 | spin_unlock(&o2hb_live_lock); |
@@ -1441,6 +1750,8 @@ static ssize_t o2hb_region_dev_write(struct o2hb_region *reg, | |||
1441 | /* Ok, we were woken. Make sure it wasn't by drop_item() */ | 1750 | /* Ok, we were woken. Make sure it wasn't by drop_item() */ |
1442 | spin_lock(&o2hb_live_lock); | 1751 | spin_lock(&o2hb_live_lock); |
1443 | hb_task = reg->hr_task; | 1752 | hb_task = reg->hr_task; |
1753 | if (o2hb_global_heartbeat_active()) | ||
1754 | set_bit(reg->hr_region_num, o2hb_live_region_bitmap); | ||
1444 | spin_unlock(&o2hb_live_lock); | 1755 | spin_unlock(&o2hb_live_lock); |
1445 | 1756 | ||
1446 | if (hb_task) | 1757 | if (hb_task) |
@@ -1448,6 +1759,10 @@ static ssize_t o2hb_region_dev_write(struct o2hb_region *reg, | |||
1448 | else | 1759 | else |
1449 | ret = -EIO; | 1760 | ret = -EIO; |
1450 | 1761 | ||
1762 | if (hb_task && o2hb_global_heartbeat_active()) | ||
1763 | printk(KERN_NOTICE "o2hb: Heartbeat started on region %s\n", | ||
1764 | config_item_name(®->hr_item)); | ||
1765 | |||
1451 | out: | 1766 | out: |
1452 | if (filp) | 1767 | if (filp) |
1453 | fput(filp); | 1768 | fput(filp); |
@@ -1586,21 +1901,94 @@ static struct o2hb_heartbeat_group *to_o2hb_heartbeat_group(struct config_group | |||
1586 | : NULL; | 1901 | : NULL; |
1587 | } | 1902 | } |
1588 | 1903 | ||
1904 | static int o2hb_debug_region_init(struct o2hb_region *reg, struct dentry *dir) | ||
1905 | { | ||
1906 | int ret = -ENOMEM; | ||
1907 | |||
1908 | reg->hr_debug_dir = | ||
1909 | debugfs_create_dir(config_item_name(®->hr_item), dir); | ||
1910 | if (!reg->hr_debug_dir) { | ||
1911 | mlog_errno(ret); | ||
1912 | goto bail; | ||
1913 | } | ||
1914 | |||
1915 | reg->hr_debug_livenodes = | ||
1916 | o2hb_debug_create(O2HB_DEBUG_LIVENODES, | ||
1917 | reg->hr_debug_dir, | ||
1918 | &(reg->hr_db_livenodes), | ||
1919 | sizeof(*(reg->hr_db_livenodes)), | ||
1920 | O2HB_DB_TYPE_REGION_LIVENODES, | ||
1921 | sizeof(reg->hr_live_node_bitmap), | ||
1922 | O2NM_MAX_NODES, reg); | ||
1923 | if (!reg->hr_debug_livenodes) { | ||
1924 | mlog_errno(ret); | ||
1925 | goto bail; | ||
1926 | } | ||
1927 | |||
1928 | reg->hr_debug_regnum = | ||
1929 | o2hb_debug_create(O2HB_DEBUG_REGION_NUMBER, | ||
1930 | reg->hr_debug_dir, | ||
1931 | &(reg->hr_db_regnum), | ||
1932 | sizeof(*(reg->hr_db_regnum)), | ||
1933 | O2HB_DB_TYPE_REGION_NUMBER, | ||
1934 | 0, O2NM_MAX_NODES, reg); | ||
1935 | if (!reg->hr_debug_regnum) { | ||
1936 | mlog_errno(ret); | ||
1937 | goto bail; | ||
1938 | } | ||
1939 | |||
1940 | reg->hr_debug_elapsed_time = | ||
1941 | o2hb_debug_create(O2HB_DEBUG_REGION_ELAPSED_TIME, | ||
1942 | reg->hr_debug_dir, | ||
1943 | &(reg->hr_db_elapsed_time), | ||
1944 | sizeof(*(reg->hr_db_elapsed_time)), | ||
1945 | O2HB_DB_TYPE_REGION_ELAPSED_TIME, | ||
1946 | 0, 0, reg); | ||
1947 | if (!reg->hr_debug_elapsed_time) { | ||
1948 | mlog_errno(ret); | ||
1949 | goto bail; | ||
1950 | } | ||
1951 | |||
1952 | ret = 0; | ||
1953 | bail: | ||
1954 | return ret; | ||
1955 | } | ||
1956 | |||
1589 | static struct config_item *o2hb_heartbeat_group_make_item(struct config_group *group, | 1957 | static struct config_item *o2hb_heartbeat_group_make_item(struct config_group *group, |
1590 | const char *name) | 1958 | const char *name) |
1591 | { | 1959 | { |
1592 | struct o2hb_region *reg = NULL; | 1960 | struct o2hb_region *reg = NULL; |
1961 | int ret; | ||
1593 | 1962 | ||
1594 | reg = kzalloc(sizeof(struct o2hb_region), GFP_KERNEL); | 1963 | reg = kzalloc(sizeof(struct o2hb_region), GFP_KERNEL); |
1595 | if (reg == NULL) | 1964 | if (reg == NULL) |
1596 | return ERR_PTR(-ENOMEM); | 1965 | return ERR_PTR(-ENOMEM); |
1597 | 1966 | ||
1598 | config_item_init_type_name(®->hr_item, name, &o2hb_region_type); | 1967 | if (strlen(name) > O2HB_MAX_REGION_NAME_LEN) |
1968 | return ERR_PTR(-ENAMETOOLONG); | ||
1599 | 1969 | ||
1600 | spin_lock(&o2hb_live_lock); | 1970 | spin_lock(&o2hb_live_lock); |
1971 | reg->hr_region_num = 0; | ||
1972 | if (o2hb_global_heartbeat_active()) { | ||
1973 | reg->hr_region_num = find_first_zero_bit(o2hb_region_bitmap, | ||
1974 | O2NM_MAX_REGIONS); | ||
1975 | if (reg->hr_region_num >= O2NM_MAX_REGIONS) { | ||
1976 | spin_unlock(&o2hb_live_lock); | ||
1977 | return ERR_PTR(-EFBIG); | ||
1978 | } | ||
1979 | set_bit(reg->hr_region_num, o2hb_region_bitmap); | ||
1980 | } | ||
1601 | list_add_tail(®->hr_all_item, &o2hb_all_regions); | 1981 | list_add_tail(®->hr_all_item, &o2hb_all_regions); |
1602 | spin_unlock(&o2hb_live_lock); | 1982 | spin_unlock(&o2hb_live_lock); |
1603 | 1983 | ||
1984 | config_item_init_type_name(®->hr_item, name, &o2hb_region_type); | ||
1985 | |||
1986 | ret = o2hb_debug_region_init(reg, o2hb_debug_dir); | ||
1987 | if (ret) { | ||
1988 | config_item_put(®->hr_item); | ||
1989 | return ERR_PTR(ret); | ||
1990 | } | ||
1991 | |||
1604 | return ®->hr_item; | 1992 | return ®->hr_item; |
1605 | } | 1993 | } |
1606 | 1994 | ||
@@ -1612,6 +2000,10 @@ static void o2hb_heartbeat_group_drop_item(struct config_group *group, | |||
1612 | 2000 | ||
1613 | /* stop the thread when the user removes the region dir */ | 2001 | /* stop the thread when the user removes the region dir */ |
1614 | spin_lock(&o2hb_live_lock); | 2002 | spin_lock(&o2hb_live_lock); |
2003 | if (o2hb_global_heartbeat_active()) { | ||
2004 | clear_bit(reg->hr_region_num, o2hb_region_bitmap); | ||
2005 | clear_bit(reg->hr_region_num, o2hb_live_region_bitmap); | ||
2006 | } | ||
1615 | hb_task = reg->hr_task; | 2007 | hb_task = reg->hr_task; |
1616 | reg->hr_task = NULL; | 2008 | reg->hr_task = NULL; |
1617 | spin_unlock(&o2hb_live_lock); | 2009 | spin_unlock(&o2hb_live_lock); |
@@ -1628,6 +2020,9 @@ static void o2hb_heartbeat_group_drop_item(struct config_group *group, | |||
1628 | wake_up(&o2hb_steady_queue); | 2020 | wake_up(&o2hb_steady_queue); |
1629 | } | 2021 | } |
1630 | 2022 | ||
2023 | if (o2hb_global_heartbeat_active()) | ||
2024 | printk(KERN_NOTICE "o2hb: Heartbeat stopped on region %s\n", | ||
2025 | config_item_name(®->hr_item)); | ||
1631 | config_item_put(item); | 2026 | config_item_put(item); |
1632 | } | 2027 | } |
1633 | 2028 | ||
@@ -1688,6 +2083,41 @@ static ssize_t o2hb_heartbeat_group_threshold_store(struct o2hb_heartbeat_group | |||
1688 | return count; | 2083 | return count; |
1689 | } | 2084 | } |
1690 | 2085 | ||
2086 | static | ||
2087 | ssize_t o2hb_heartbeat_group_mode_show(struct o2hb_heartbeat_group *group, | ||
2088 | char *page) | ||
2089 | { | ||
2090 | return sprintf(page, "%s\n", | ||
2091 | o2hb_heartbeat_mode_desc[o2hb_heartbeat_mode]); | ||
2092 | } | ||
2093 | |||
2094 | static | ||
2095 | ssize_t o2hb_heartbeat_group_mode_store(struct o2hb_heartbeat_group *group, | ||
2096 | const char *page, size_t count) | ||
2097 | { | ||
2098 | unsigned int i; | ||
2099 | int ret; | ||
2100 | size_t len; | ||
2101 | |||
2102 | len = (page[count - 1] == '\n') ? count - 1 : count; | ||
2103 | if (!len) | ||
2104 | return -EINVAL; | ||
2105 | |||
2106 | for (i = 0; i < O2HB_HEARTBEAT_NUM_MODES; ++i) { | ||
2107 | if (strnicmp(page, o2hb_heartbeat_mode_desc[i], len)) | ||
2108 | continue; | ||
2109 | |||
2110 | ret = o2hb_global_hearbeat_mode_set(i); | ||
2111 | if (!ret) | ||
2112 | printk(KERN_NOTICE "o2hb: Heartbeat mode set to %s\n", | ||
2113 | o2hb_heartbeat_mode_desc[i]); | ||
2114 | return count; | ||
2115 | } | ||
2116 | |||
2117 | return -EINVAL; | ||
2118 | |||
2119 | } | ||
2120 | |||
1691 | static struct o2hb_heartbeat_group_attribute o2hb_heartbeat_group_attr_threshold = { | 2121 | static struct o2hb_heartbeat_group_attribute o2hb_heartbeat_group_attr_threshold = { |
1692 | .attr = { .ca_owner = THIS_MODULE, | 2122 | .attr = { .ca_owner = THIS_MODULE, |
1693 | .ca_name = "dead_threshold", | 2123 | .ca_name = "dead_threshold", |
@@ -1696,8 +2126,17 @@ static struct o2hb_heartbeat_group_attribute o2hb_heartbeat_group_attr_threshold | |||
1696 | .store = o2hb_heartbeat_group_threshold_store, | 2126 | .store = o2hb_heartbeat_group_threshold_store, |
1697 | }; | 2127 | }; |
1698 | 2128 | ||
2129 | static struct o2hb_heartbeat_group_attribute o2hb_heartbeat_group_attr_mode = { | ||
2130 | .attr = { .ca_owner = THIS_MODULE, | ||
2131 | .ca_name = "mode", | ||
2132 | .ca_mode = S_IRUGO | S_IWUSR }, | ||
2133 | .show = o2hb_heartbeat_group_mode_show, | ||
2134 | .store = o2hb_heartbeat_group_mode_store, | ||
2135 | }; | ||
2136 | |||
1699 | static struct configfs_attribute *o2hb_heartbeat_group_attrs[] = { | 2137 | static struct configfs_attribute *o2hb_heartbeat_group_attrs[] = { |
1700 | &o2hb_heartbeat_group_attr_threshold.attr, | 2138 | &o2hb_heartbeat_group_attr_threshold.attr, |
2139 | &o2hb_heartbeat_group_attr_mode.attr, | ||
1701 | NULL, | 2140 | NULL, |
1702 | }; | 2141 | }; |
1703 | 2142 | ||
@@ -1963,3 +2402,34 @@ void o2hb_stop_all_regions(void) | |||
1963 | spin_unlock(&o2hb_live_lock); | 2402 | spin_unlock(&o2hb_live_lock); |
1964 | } | 2403 | } |
1965 | EXPORT_SYMBOL_GPL(o2hb_stop_all_regions); | 2404 | EXPORT_SYMBOL_GPL(o2hb_stop_all_regions); |
2405 | |||
2406 | int o2hb_get_all_regions(char *region_uuids, u8 max_regions) | ||
2407 | { | ||
2408 | struct o2hb_region *reg; | ||
2409 | int numregs = 0; | ||
2410 | char *p; | ||
2411 | |||
2412 | spin_lock(&o2hb_live_lock); | ||
2413 | |||
2414 | p = region_uuids; | ||
2415 | list_for_each_entry(reg, &o2hb_all_regions, hr_all_item) { | ||
2416 | mlog(0, "Region: %s\n", config_item_name(®->hr_item)); | ||
2417 | if (numregs < max_regions) { | ||
2418 | memcpy(p, config_item_name(®->hr_item), | ||
2419 | O2HB_MAX_REGION_NAME_LEN); | ||
2420 | p += O2HB_MAX_REGION_NAME_LEN; | ||
2421 | } | ||
2422 | numregs++; | ||
2423 | } | ||
2424 | |||
2425 | spin_unlock(&o2hb_live_lock); | ||
2426 | |||
2427 | return numregs; | ||
2428 | } | ||
2429 | EXPORT_SYMBOL_GPL(o2hb_get_all_regions); | ||
2430 | |||
2431 | int o2hb_global_heartbeat_active(void) | ||
2432 | { | ||
2433 | return (o2hb_heartbeat_mode == O2HB_HEARTBEAT_GLOBAL); | ||
2434 | } | ||
2435 | EXPORT_SYMBOL(o2hb_global_heartbeat_active); | ||
diff --git a/fs/ocfs2/cluster/heartbeat.h b/fs/ocfs2/cluster/heartbeat.h index 2f1649253b49..00ad8e8fea51 100644 --- a/fs/ocfs2/cluster/heartbeat.h +++ b/fs/ocfs2/cluster/heartbeat.h | |||
@@ -31,6 +31,8 @@ | |||
31 | 31 | ||
32 | #define O2HB_REGION_TIMEOUT_MS 2000 | 32 | #define O2HB_REGION_TIMEOUT_MS 2000 |
33 | 33 | ||
34 | #define O2HB_MAX_REGION_NAME_LEN 32 | ||
35 | |||
34 | /* number of changes to be seen as live */ | 36 | /* number of changes to be seen as live */ |
35 | #define O2HB_LIVE_THRESHOLD 2 | 37 | #define O2HB_LIVE_THRESHOLD 2 |
36 | /* number of equal samples to be seen as dead */ | 38 | /* number of equal samples to be seen as dead */ |
@@ -81,5 +83,7 @@ int o2hb_check_node_heartbeating(u8 node_num); | |||
81 | int o2hb_check_node_heartbeating_from_callback(u8 node_num); | 83 | int o2hb_check_node_heartbeating_from_callback(u8 node_num); |
82 | int o2hb_check_local_node_heartbeating(void); | 84 | int o2hb_check_local_node_heartbeating(void); |
83 | void o2hb_stop_all_regions(void); | 85 | void o2hb_stop_all_regions(void); |
86 | int o2hb_get_all_regions(char *region_uuids, u8 numregions); | ||
87 | int o2hb_global_heartbeat_active(void); | ||
84 | 88 | ||
85 | #endif /* O2CLUSTER_HEARTBEAT_H */ | 89 | #endif /* O2CLUSTER_HEARTBEAT_H */ |
diff --git a/fs/ocfs2/cluster/masklog.h b/fs/ocfs2/cluster/masklog.h index fd96e2a2fa56..ea2ed9f56c94 100644 --- a/fs/ocfs2/cluster/masklog.h +++ b/fs/ocfs2/cluster/masklog.h | |||
@@ -119,7 +119,8 @@ | |||
119 | #define ML_ERROR 0x0000000100000000ULL /* sent to KERN_ERR */ | 119 | #define ML_ERROR 0x0000000100000000ULL /* sent to KERN_ERR */ |
120 | #define ML_NOTICE 0x0000000200000000ULL /* setn to KERN_NOTICE */ | 120 | #define ML_NOTICE 0x0000000200000000ULL /* setn to KERN_NOTICE */ |
121 | #define ML_KTHREAD 0x0000000400000000ULL /* kernel thread activity */ | 121 | #define ML_KTHREAD 0x0000000400000000ULL /* kernel thread activity */ |
122 | #define ML_RESERVATIONS 0x0000000800000000ULL /* ocfs2 alloc reservations */ | 122 | #define ML_RESERVATIONS 0x0000000800000000ULL /* ocfs2 alloc reservations */ |
123 | #define ML_CLUSTER 0x0000001000000000ULL /* cluster stack */ | ||
123 | 124 | ||
124 | #define MLOG_INITIAL_AND_MASK (ML_ERROR|ML_NOTICE) | 125 | #define MLOG_INITIAL_AND_MASK (ML_ERROR|ML_NOTICE) |
125 | #define MLOG_INITIAL_NOT_MASK (ML_ENTRY|ML_EXIT) | 126 | #define MLOG_INITIAL_NOT_MASK (ML_ENTRY|ML_EXIT) |
diff --git a/fs/ocfs2/cluster/nodemanager.c b/fs/ocfs2/cluster/nodemanager.c index ed0c9f367fed..bb240647ca5f 100644 --- a/fs/ocfs2/cluster/nodemanager.c +++ b/fs/ocfs2/cluster/nodemanager.c | |||
@@ -711,6 +711,8 @@ static struct config_item *o2nm_node_group_make_item(struct config_group *group, | |||
711 | config_item_init_type_name(&node->nd_item, name, &o2nm_node_type); | 711 | config_item_init_type_name(&node->nd_item, name, &o2nm_node_type); |
712 | spin_lock_init(&node->nd_lock); | 712 | spin_lock_init(&node->nd_lock); |
713 | 713 | ||
714 | mlog(ML_CLUSTER, "o2nm: Registering node %s\n", name); | ||
715 | |||
714 | return &node->nd_item; | 716 | return &node->nd_item; |
715 | } | 717 | } |
716 | 718 | ||
@@ -744,6 +746,9 @@ static void o2nm_node_group_drop_item(struct config_group *group, | |||
744 | } | 746 | } |
745 | write_unlock(&cluster->cl_nodes_lock); | 747 | write_unlock(&cluster->cl_nodes_lock); |
746 | 748 | ||
749 | mlog(ML_CLUSTER, "o2nm: Unregistered node %s\n", | ||
750 | config_item_name(&node->nd_item)); | ||
751 | |||
747 | config_item_put(item); | 752 | config_item_put(item); |
748 | } | 753 | } |
749 | 754 | ||
diff --git a/fs/ocfs2/cluster/ocfs2_nodemanager.h b/fs/ocfs2/cluster/ocfs2_nodemanager.h index 5b9854bad571..49b594325bec 100644 --- a/fs/ocfs2/cluster/ocfs2_nodemanager.h +++ b/fs/ocfs2/cluster/ocfs2_nodemanager.h | |||
@@ -36,4 +36,10 @@ | |||
36 | /* host name, group name, cluster name all 64 bytes */ | 36 | /* host name, group name, cluster name all 64 bytes */ |
37 | #define O2NM_MAX_NAME_LEN 64 // __NEW_UTS_LEN | 37 | #define O2NM_MAX_NAME_LEN 64 // __NEW_UTS_LEN |
38 | 38 | ||
39 | /* | ||
40 | * Maximum number of global heartbeat regions allowed. | ||
41 | * **CAUTION** Changing this number will break dlm compatibility. | ||
42 | */ | ||
43 | #define O2NM_MAX_REGIONS 32 | ||
44 | |||
39 | #endif /* _OCFS2_NODEMANAGER_H */ | 45 | #endif /* _OCFS2_NODEMANAGER_H */ |
diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c index 1361997cf205..9aa426e42123 100644 --- a/fs/ocfs2/cluster/tcp.c +++ b/fs/ocfs2/cluster/tcp.c | |||
@@ -977,7 +977,7 @@ static int o2net_tx_can_proceed(struct o2net_node *nn, | |||
977 | int o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec, | 977 | int o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec, |
978 | size_t caller_veclen, u8 target_node, int *status) | 978 | size_t caller_veclen, u8 target_node, int *status) |
979 | { | 979 | { |
980 | int ret; | 980 | int ret = 0; |
981 | struct o2net_msg *msg = NULL; | 981 | struct o2net_msg *msg = NULL; |
982 | size_t veclen, caller_bytes = 0; | 982 | size_t veclen, caller_bytes = 0; |
983 | struct kvec *vec = NULL; | 983 | struct kvec *vec = NULL; |
@@ -1696,6 +1696,9 @@ static void o2net_hb_node_down_cb(struct o2nm_node *node, int node_num, | |||
1696 | { | 1696 | { |
1697 | o2quo_hb_down(node_num); | 1697 | o2quo_hb_down(node_num); |
1698 | 1698 | ||
1699 | if (!node) | ||
1700 | return; | ||
1701 | |||
1699 | if (node_num != o2nm_this_node()) | 1702 | if (node_num != o2nm_this_node()) |
1700 | o2net_disconnect_node(node); | 1703 | o2net_disconnect_node(node); |
1701 | 1704 | ||
@@ -1709,6 +1712,8 @@ static void o2net_hb_node_up_cb(struct o2nm_node *node, int node_num, | |||
1709 | 1712 | ||
1710 | o2quo_hb_up(node_num); | 1713 | o2quo_hb_up(node_num); |
1711 | 1714 | ||
1715 | BUG_ON(!node); | ||
1716 | |||
1712 | /* ensure an immediate connect attempt */ | 1717 | /* ensure an immediate connect attempt */ |
1713 | nn->nn_last_connect_attempt = jiffies - | 1718 | nn->nn_last_connect_attempt = jiffies - |
1714 | (msecs_to_jiffies(o2net_reconnect_delay()) + 1); | 1719 | (msecs_to_jiffies(o2net_reconnect_delay()) + 1); |
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index f04ebcfffc4a..c49f6de0e7ab 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c | |||
@@ -3931,6 +3931,15 @@ static int ocfs2_dx_dir_rebalance(struct ocfs2_super *osb, struct inode *dir, | |||
3931 | goto out_commit; | 3931 | goto out_commit; |
3932 | } | 3932 | } |
3933 | 3933 | ||
3934 | cpos = split_hash; | ||
3935 | ret = ocfs2_dx_dir_new_cluster(dir, &et, cpos, handle, | ||
3936 | data_ac, meta_ac, new_dx_leaves, | ||
3937 | num_dx_leaves); | ||
3938 | if (ret) { | ||
3939 | mlog_errno(ret); | ||
3940 | goto out_commit; | ||
3941 | } | ||
3942 | |||
3934 | for (i = 0; i < num_dx_leaves; i++) { | 3943 | for (i = 0; i < num_dx_leaves; i++) { |
3935 | ret = ocfs2_journal_access_dl(handle, INODE_CACHE(dir), | 3944 | ret = ocfs2_journal_access_dl(handle, INODE_CACHE(dir), |
3936 | orig_dx_leaves[i], | 3945 | orig_dx_leaves[i], |
@@ -3939,15 +3948,14 @@ static int ocfs2_dx_dir_rebalance(struct ocfs2_super *osb, struct inode *dir, | |||
3939 | mlog_errno(ret); | 3948 | mlog_errno(ret); |
3940 | goto out_commit; | 3949 | goto out_commit; |
3941 | } | 3950 | } |
3942 | } | ||
3943 | 3951 | ||
3944 | cpos = split_hash; | 3952 | ret = ocfs2_journal_access_dl(handle, INODE_CACHE(dir), |
3945 | ret = ocfs2_dx_dir_new_cluster(dir, &et, cpos, handle, | 3953 | new_dx_leaves[i], |
3946 | data_ac, meta_ac, new_dx_leaves, | 3954 | OCFS2_JOURNAL_ACCESS_WRITE); |
3947 | num_dx_leaves); | 3955 | if (ret) { |
3948 | if (ret) { | 3956 | mlog_errno(ret); |
3949 | mlog_errno(ret); | 3957 | goto out_commit; |
3950 | goto out_commit; | 3958 | } |
3951 | } | 3959 | } |
3952 | 3960 | ||
3953 | ocfs2_dx_dir_transfer_leaf(dir, split_hash, handle, tmp_dx_leaf, | 3961 | ocfs2_dx_dir_transfer_leaf(dir, split_hash, handle, tmp_dx_leaf, |
diff --git a/fs/ocfs2/dlm/dlmcommon.h b/fs/ocfs2/dlm/dlmcommon.h index 4b6ae2c13b47..b36d0bf77a5a 100644 --- a/fs/ocfs2/dlm/dlmcommon.h +++ b/fs/ocfs2/dlm/dlmcommon.h | |||
@@ -445,7 +445,9 @@ enum { | |||
445 | DLM_LOCK_REQUEST_MSG, /* 515 */ | 445 | DLM_LOCK_REQUEST_MSG, /* 515 */ |
446 | DLM_RECO_DATA_DONE_MSG, /* 516 */ | 446 | DLM_RECO_DATA_DONE_MSG, /* 516 */ |
447 | DLM_BEGIN_RECO_MSG, /* 517 */ | 447 | DLM_BEGIN_RECO_MSG, /* 517 */ |
448 | DLM_FINALIZE_RECO_MSG /* 518 */ | 448 | DLM_FINALIZE_RECO_MSG, /* 518 */ |
449 | DLM_QUERY_REGION, /* 519 */ | ||
450 | DLM_QUERY_NODEINFO, /* 520 */ | ||
449 | }; | 451 | }; |
450 | 452 | ||
451 | struct dlm_reco_node_data | 453 | struct dlm_reco_node_data |
@@ -727,6 +729,31 @@ struct dlm_cancel_join | |||
727 | u8 domain[O2NM_MAX_NAME_LEN]; | 729 | u8 domain[O2NM_MAX_NAME_LEN]; |
728 | }; | 730 | }; |
729 | 731 | ||
732 | struct dlm_query_region { | ||
733 | u8 qr_node; | ||
734 | u8 qr_numregions; | ||
735 | u8 qr_namelen; | ||
736 | u8 pad1; | ||
737 | u8 qr_domain[O2NM_MAX_NAME_LEN]; | ||
738 | u8 qr_regions[O2HB_MAX_REGION_NAME_LEN * O2NM_MAX_REGIONS]; | ||
739 | }; | ||
740 | |||
741 | struct dlm_node_info { | ||
742 | u8 ni_nodenum; | ||
743 | u8 pad1; | ||
744 | u16 ni_ipv4_port; | ||
745 | u32 ni_ipv4_address; | ||
746 | }; | ||
747 | |||
748 | struct dlm_query_nodeinfo { | ||
749 | u8 qn_nodenum; | ||
750 | u8 qn_numnodes; | ||
751 | u8 qn_namelen; | ||
752 | u8 pad1; | ||
753 | u8 qn_domain[O2NM_MAX_NAME_LEN]; | ||
754 | struct dlm_node_info qn_nodes[O2NM_MAX_NODES]; | ||
755 | }; | ||
756 | |||
730 | struct dlm_exit_domain | 757 | struct dlm_exit_domain |
731 | { | 758 | { |
732 | u8 node_idx; | 759 | u8 node_idx; |
@@ -1030,6 +1057,7 @@ int dlm_drop_lockres_ref(struct dlm_ctxt *dlm, | |||
1030 | struct dlm_lock_resource *res); | 1057 | struct dlm_lock_resource *res); |
1031 | void dlm_clean_master_list(struct dlm_ctxt *dlm, | 1058 | void dlm_clean_master_list(struct dlm_ctxt *dlm, |
1032 | u8 dead_node); | 1059 | u8 dead_node); |
1060 | void dlm_force_free_mles(struct dlm_ctxt *dlm); | ||
1033 | int dlm_lock_basts_flushed(struct dlm_ctxt *dlm, struct dlm_lock *lock); | 1061 | int dlm_lock_basts_flushed(struct dlm_ctxt *dlm, struct dlm_lock *lock); |
1034 | int __dlm_lockres_has_locks(struct dlm_lock_resource *res); | 1062 | int __dlm_lockres_has_locks(struct dlm_lock_resource *res); |
1035 | int __dlm_lockres_unused(struct dlm_lock_resource *res); | 1063 | int __dlm_lockres_unused(struct dlm_lock_resource *res); |
diff --git a/fs/ocfs2/dlm/dlmdebug.c b/fs/ocfs2/dlm/dlmdebug.c index 26ff2e185b1e..272ec8631a51 100644 --- a/fs/ocfs2/dlm/dlmdebug.c +++ b/fs/ocfs2/dlm/dlmdebug.c | |||
@@ -636,8 +636,14 @@ static void *lockres_seq_start(struct seq_file *m, loff_t *pos) | |||
636 | spin_lock(&dlm->track_lock); | 636 | spin_lock(&dlm->track_lock); |
637 | if (oldres) | 637 | if (oldres) |
638 | track_list = &oldres->tracking; | 638 | track_list = &oldres->tracking; |
639 | else | 639 | else { |
640 | track_list = &dlm->tracking_list; | 640 | track_list = &dlm->tracking_list; |
641 | if (list_empty(track_list)) { | ||
642 | dl = NULL; | ||
643 | spin_unlock(&dlm->track_lock); | ||
644 | goto bail; | ||
645 | } | ||
646 | } | ||
641 | 647 | ||
642 | list_for_each_entry(res, track_list, tracking) { | 648 | list_for_each_entry(res, track_list, tracking) { |
643 | if (&res->tracking == &dlm->tracking_list) | 649 | if (&res->tracking == &dlm->tracking_list) |
@@ -660,6 +666,7 @@ static void *lockres_seq_start(struct seq_file *m, loff_t *pos) | |||
660 | } else | 666 | } else |
661 | dl = NULL; | 667 | dl = NULL; |
662 | 668 | ||
669 | bail: | ||
663 | /* passed to seq_show */ | 670 | /* passed to seq_show */ |
664 | return dl; | 671 | return dl; |
665 | } | 672 | } |
@@ -775,7 +782,9 @@ static int debug_state_print(struct dlm_ctxt *dlm, struct debug_buffer *db) | |||
775 | 782 | ||
776 | /* Domain: xxxxxxxxxx Key: 0xdfbac769 */ | 783 | /* Domain: xxxxxxxxxx Key: 0xdfbac769 */ |
777 | out += snprintf(db->buf + out, db->len - out, | 784 | out += snprintf(db->buf + out, db->len - out, |
778 | "Domain: %s Key: 0x%08x\n", dlm->name, dlm->key); | 785 | "Domain: %s Key: 0x%08x Protocol: %d.%d\n", |
786 | dlm->name, dlm->key, dlm->dlm_locking_proto.pv_major, | ||
787 | dlm->dlm_locking_proto.pv_minor); | ||
779 | 788 | ||
780 | /* Thread Pid: xxx Node: xxx State: xxxxx */ | 789 | /* Thread Pid: xxx Node: xxx State: xxxxx */ |
781 | out += snprintf(db->buf + out, db->len - out, | 790 | out += snprintf(db->buf + out, db->len - out, |
diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c index 153abb5abef0..58a93b953735 100644 --- a/fs/ocfs2/dlm/dlmdomain.c +++ b/fs/ocfs2/dlm/dlmdomain.c | |||
@@ -128,10 +128,14 @@ static DECLARE_WAIT_QUEUE_HEAD(dlm_domain_events); | |||
128 | * will have a negotiated version with the same major number and a minor | 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 | 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. | 130 | * be used to determine what a running domain is actually using. |
131 | * | ||
132 | * New in version 1.1: | ||
133 | * - Message DLM_QUERY_REGION added to support global heartbeat | ||
134 | * - Message DLM_QUERY_NODEINFO added to allow online node removes | ||
131 | */ | 135 | */ |
132 | static const struct dlm_protocol_version dlm_protocol = { | 136 | static const struct dlm_protocol_version dlm_protocol = { |
133 | .pv_major = 1, | 137 | .pv_major = 1, |
134 | .pv_minor = 0, | 138 | .pv_minor = 1, |
135 | }; | 139 | }; |
136 | 140 | ||
137 | #define DLM_DOMAIN_BACKOFF_MS 200 | 141 | #define DLM_DOMAIN_BACKOFF_MS 200 |
@@ -142,6 +146,8 @@ static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data, | |||
142 | void **ret_data); | 146 | void **ret_data); |
143 | static int dlm_cancel_join_handler(struct o2net_msg *msg, u32 len, void *data, | 147 | static int dlm_cancel_join_handler(struct o2net_msg *msg, u32 len, void *data, |
144 | void **ret_data); | 148 | void **ret_data); |
149 | static int dlm_query_region_handler(struct o2net_msg *msg, u32 len, | ||
150 | void *data, void **ret_data); | ||
145 | static int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data, | 151 | static int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data, |
146 | void **ret_data); | 152 | void **ret_data); |
147 | static int dlm_protocol_compare(struct dlm_protocol_version *existing, | 153 | static int dlm_protocol_compare(struct dlm_protocol_version *existing, |
@@ -693,6 +699,7 @@ void dlm_unregister_domain(struct dlm_ctxt *dlm) | |||
693 | 699 | ||
694 | dlm_mark_domain_leaving(dlm); | 700 | dlm_mark_domain_leaving(dlm); |
695 | dlm_leave_domain(dlm); | 701 | dlm_leave_domain(dlm); |
702 | dlm_force_free_mles(dlm); | ||
696 | dlm_complete_dlm_shutdown(dlm); | 703 | dlm_complete_dlm_shutdown(dlm); |
697 | } | 704 | } |
698 | dlm_put(dlm); | 705 | dlm_put(dlm); |
@@ -920,6 +927,370 @@ static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data, | |||
920 | return 0; | 927 | return 0; |
921 | } | 928 | } |
922 | 929 | ||
930 | static int dlm_match_regions(struct dlm_ctxt *dlm, | ||
931 | struct dlm_query_region *qr) | ||
932 | { | ||
933 | char *local = NULL, *remote = qr->qr_regions; | ||
934 | char *l, *r; | ||
935 | int localnr, i, j, foundit; | ||
936 | int status = 0; | ||
937 | |||
938 | if (!o2hb_global_heartbeat_active()) { | ||
939 | if (qr->qr_numregions) { | ||
940 | mlog(ML_ERROR, "Domain %s: Joining node %d has global " | ||
941 | "heartbeat enabled but local node %d does not\n", | ||
942 | qr->qr_domain, qr->qr_node, dlm->node_num); | ||
943 | status = -EINVAL; | ||
944 | } | ||
945 | goto bail; | ||
946 | } | ||
947 | |||
948 | if (o2hb_global_heartbeat_active() && !qr->qr_numregions) { | ||
949 | mlog(ML_ERROR, "Domain %s: Local node %d has global " | ||
950 | "heartbeat enabled but joining node %d does not\n", | ||
951 | qr->qr_domain, dlm->node_num, qr->qr_node); | ||
952 | status = -EINVAL; | ||
953 | goto bail; | ||
954 | } | ||
955 | |||
956 | r = remote; | ||
957 | for (i = 0; i < qr->qr_numregions; ++i) { | ||
958 | mlog(0, "Region %.*s\n", O2HB_MAX_REGION_NAME_LEN, r); | ||
959 | r += O2HB_MAX_REGION_NAME_LEN; | ||
960 | } | ||
961 | |||
962 | local = kmalloc(sizeof(qr->qr_regions), GFP_KERNEL); | ||
963 | if (!local) { | ||
964 | status = -ENOMEM; | ||
965 | goto bail; | ||
966 | } | ||
967 | |||
968 | localnr = o2hb_get_all_regions(local, O2NM_MAX_REGIONS); | ||
969 | |||
970 | /* compare local regions with remote */ | ||
971 | l = local; | ||
972 | for (i = 0; i < localnr; ++i) { | ||
973 | foundit = 0; | ||
974 | r = remote; | ||
975 | for (j = 0; j <= qr->qr_numregions; ++j) { | ||
976 | if (!memcmp(l, r, O2HB_MAX_REGION_NAME_LEN)) { | ||
977 | foundit = 1; | ||
978 | break; | ||
979 | } | ||
980 | r += O2HB_MAX_REGION_NAME_LEN; | ||
981 | } | ||
982 | if (!foundit) { | ||
983 | status = -EINVAL; | ||
984 | mlog(ML_ERROR, "Domain %s: Region '%.*s' registered " | ||
985 | "in local node %d but not in joining node %d\n", | ||
986 | qr->qr_domain, O2HB_MAX_REGION_NAME_LEN, l, | ||
987 | dlm->node_num, qr->qr_node); | ||
988 | goto bail; | ||
989 | } | ||
990 | l += O2HB_MAX_REGION_NAME_LEN; | ||
991 | } | ||
992 | |||
993 | /* compare remote with local regions */ | ||
994 | r = remote; | ||
995 | for (i = 0; i < qr->qr_numregions; ++i) { | ||
996 | foundit = 0; | ||
997 | l = local; | ||
998 | for (j = 0; j < localnr; ++j) { | ||
999 | if (!memcmp(r, l, O2HB_MAX_REGION_NAME_LEN)) { | ||
1000 | foundit = 1; | ||
1001 | break; | ||
1002 | } | ||
1003 | l += O2HB_MAX_REGION_NAME_LEN; | ||
1004 | } | ||
1005 | if (!foundit) { | ||
1006 | status = -EINVAL; | ||
1007 | mlog(ML_ERROR, "Domain %s: Region '%.*s' registered " | ||
1008 | "in joining node %d but not in local node %d\n", | ||
1009 | qr->qr_domain, O2HB_MAX_REGION_NAME_LEN, r, | ||
1010 | qr->qr_node, dlm->node_num); | ||
1011 | goto bail; | ||
1012 | } | ||
1013 | r += O2HB_MAX_REGION_NAME_LEN; | ||
1014 | } | ||
1015 | |||
1016 | bail: | ||
1017 | kfree(local); | ||
1018 | |||
1019 | return status; | ||
1020 | } | ||
1021 | |||
1022 | static int dlm_send_regions(struct dlm_ctxt *dlm, unsigned long *node_map) | ||
1023 | { | ||
1024 | struct dlm_query_region *qr = NULL; | ||
1025 | int status, ret = 0, i; | ||
1026 | char *p; | ||
1027 | |||
1028 | if (find_next_bit(node_map, O2NM_MAX_NODES, 0) >= O2NM_MAX_NODES) | ||
1029 | goto bail; | ||
1030 | |||
1031 | qr = kzalloc(sizeof(struct dlm_query_region), GFP_KERNEL); | ||
1032 | if (!qr) { | ||
1033 | ret = -ENOMEM; | ||
1034 | mlog_errno(ret); | ||
1035 | goto bail; | ||
1036 | } | ||
1037 | |||
1038 | qr->qr_node = dlm->node_num; | ||
1039 | qr->qr_namelen = strlen(dlm->name); | ||
1040 | memcpy(qr->qr_domain, dlm->name, qr->qr_namelen); | ||
1041 | /* if local hb, the numregions will be zero */ | ||
1042 | if (o2hb_global_heartbeat_active()) | ||
1043 | qr->qr_numregions = o2hb_get_all_regions(qr->qr_regions, | ||
1044 | O2NM_MAX_REGIONS); | ||
1045 | |||
1046 | p = qr->qr_regions; | ||
1047 | for (i = 0; i < qr->qr_numregions; ++i, p += O2HB_MAX_REGION_NAME_LEN) | ||
1048 | mlog(0, "Region %.*s\n", O2HB_MAX_REGION_NAME_LEN, p); | ||
1049 | |||
1050 | i = -1; | ||
1051 | while ((i = find_next_bit(node_map, O2NM_MAX_NODES, | ||
1052 | i + 1)) < O2NM_MAX_NODES) { | ||
1053 | if (i == dlm->node_num) | ||
1054 | continue; | ||
1055 | |||
1056 | mlog(0, "Sending regions to node %d\n", i); | ||
1057 | |||
1058 | ret = o2net_send_message(DLM_QUERY_REGION, DLM_MOD_KEY, qr, | ||
1059 | sizeof(struct dlm_query_region), | ||
1060 | i, &status); | ||
1061 | if (ret >= 0) | ||
1062 | ret = status; | ||
1063 | if (ret) { | ||
1064 | mlog(ML_ERROR, "Region mismatch %d, node %d\n", | ||
1065 | ret, i); | ||
1066 | break; | ||
1067 | } | ||
1068 | } | ||
1069 | |||
1070 | bail: | ||
1071 | kfree(qr); | ||
1072 | return ret; | ||
1073 | } | ||
1074 | |||
1075 | static int dlm_query_region_handler(struct o2net_msg *msg, u32 len, | ||
1076 | void *data, void **ret_data) | ||
1077 | { | ||
1078 | struct dlm_query_region *qr; | ||
1079 | struct dlm_ctxt *dlm = NULL; | ||
1080 | int status = 0; | ||
1081 | int locked = 0; | ||
1082 | |||
1083 | qr = (struct dlm_query_region *) msg->buf; | ||
1084 | |||
1085 | mlog(0, "Node %u queries hb regions on domain %s\n", qr->qr_node, | ||
1086 | qr->qr_domain); | ||
1087 | |||
1088 | status = -EINVAL; | ||
1089 | |||
1090 | spin_lock(&dlm_domain_lock); | ||
1091 | dlm = __dlm_lookup_domain_full(qr->qr_domain, qr->qr_namelen); | ||
1092 | if (!dlm) { | ||
1093 | mlog(ML_ERROR, "Node %d queried hb regions on domain %s " | ||
1094 | "before join domain\n", qr->qr_node, qr->qr_domain); | ||
1095 | goto bail; | ||
1096 | } | ||
1097 | |||
1098 | spin_lock(&dlm->spinlock); | ||
1099 | locked = 1; | ||
1100 | if (dlm->joining_node != qr->qr_node) { | ||
1101 | mlog(ML_ERROR, "Node %d queried hb regions on domain %s " | ||
1102 | "but joining node is %d\n", qr->qr_node, qr->qr_domain, | ||
1103 | dlm->joining_node); | ||
1104 | goto bail; | ||
1105 | } | ||
1106 | |||
1107 | /* Support for global heartbeat was added in 1.1 */ | ||
1108 | if (dlm->dlm_locking_proto.pv_major == 1 && | ||
1109 | dlm->dlm_locking_proto.pv_minor == 0) { | ||
1110 | mlog(ML_ERROR, "Node %d queried hb regions on domain %s " | ||
1111 | "but active dlm protocol is %d.%d\n", qr->qr_node, | ||
1112 | qr->qr_domain, dlm->dlm_locking_proto.pv_major, | ||
1113 | dlm->dlm_locking_proto.pv_minor); | ||
1114 | goto bail; | ||
1115 | } | ||
1116 | |||
1117 | status = dlm_match_regions(dlm, qr); | ||
1118 | |||
1119 | bail: | ||
1120 | if (locked) | ||
1121 | spin_unlock(&dlm->spinlock); | ||
1122 | spin_unlock(&dlm_domain_lock); | ||
1123 | |||
1124 | return status; | ||
1125 | } | ||
1126 | |||
1127 | static int dlm_match_nodes(struct dlm_ctxt *dlm, struct dlm_query_nodeinfo *qn) | ||
1128 | { | ||
1129 | struct o2nm_node *local; | ||
1130 | struct dlm_node_info *remote; | ||
1131 | int i, j; | ||
1132 | int status = 0; | ||
1133 | |||
1134 | for (j = 0; j < qn->qn_numnodes; ++j) | ||
1135 | mlog(0, "Node %3d, %pI4:%u\n", qn->qn_nodes[j].ni_nodenum, | ||
1136 | &(qn->qn_nodes[j].ni_ipv4_address), | ||
1137 | ntohs(qn->qn_nodes[j].ni_ipv4_port)); | ||
1138 | |||
1139 | for (i = 0; i < O2NM_MAX_NODES && !status; ++i) { | ||
1140 | local = o2nm_get_node_by_num(i); | ||
1141 | remote = NULL; | ||
1142 | for (j = 0; j < qn->qn_numnodes; ++j) { | ||
1143 | if (qn->qn_nodes[j].ni_nodenum == i) { | ||
1144 | remote = &(qn->qn_nodes[j]); | ||
1145 | break; | ||
1146 | } | ||
1147 | } | ||
1148 | |||
1149 | if (!local && !remote) | ||
1150 | continue; | ||
1151 | |||
1152 | if ((local && !remote) || (!local && remote)) | ||
1153 | status = -EINVAL; | ||
1154 | |||
1155 | if (!status && | ||
1156 | ((remote->ni_nodenum != local->nd_num) || | ||
1157 | (remote->ni_ipv4_port != local->nd_ipv4_port) || | ||
1158 | (remote->ni_ipv4_address != local->nd_ipv4_address))) | ||
1159 | status = -EINVAL; | ||
1160 | |||
1161 | if (status) { | ||
1162 | if (remote && !local) | ||
1163 | mlog(ML_ERROR, "Domain %s: Node %d (%pI4:%u) " | ||
1164 | "registered in joining node %d but not in " | ||
1165 | "local node %d\n", qn->qn_domain, | ||
1166 | remote->ni_nodenum, | ||
1167 | &(remote->ni_ipv4_address), | ||
1168 | ntohs(remote->ni_ipv4_port), | ||
1169 | qn->qn_nodenum, dlm->node_num); | ||
1170 | if (local && !remote) | ||
1171 | mlog(ML_ERROR, "Domain %s: Node %d (%pI4:%u) " | ||
1172 | "registered in local node %d but not in " | ||
1173 | "joining node %d\n", qn->qn_domain, | ||
1174 | local->nd_num, &(local->nd_ipv4_address), | ||
1175 | ntohs(local->nd_ipv4_port), | ||
1176 | dlm->node_num, qn->qn_nodenum); | ||
1177 | BUG_ON((!local && !remote)); | ||
1178 | } | ||
1179 | |||
1180 | if (local) | ||
1181 | o2nm_node_put(local); | ||
1182 | } | ||
1183 | |||
1184 | return status; | ||
1185 | } | ||
1186 | |||
1187 | static int dlm_send_nodeinfo(struct dlm_ctxt *dlm, unsigned long *node_map) | ||
1188 | { | ||
1189 | struct dlm_query_nodeinfo *qn = NULL; | ||
1190 | struct o2nm_node *node; | ||
1191 | int ret = 0, status, count, i; | ||
1192 | |||
1193 | if (find_next_bit(node_map, O2NM_MAX_NODES, 0) >= O2NM_MAX_NODES) | ||
1194 | goto bail; | ||
1195 | |||
1196 | qn = kzalloc(sizeof(struct dlm_query_nodeinfo), GFP_KERNEL); | ||
1197 | if (!qn) { | ||
1198 | ret = -ENOMEM; | ||
1199 | mlog_errno(ret); | ||
1200 | goto bail; | ||
1201 | } | ||
1202 | |||
1203 | for (i = 0, count = 0; i < O2NM_MAX_NODES; ++i) { | ||
1204 | node = o2nm_get_node_by_num(i); | ||
1205 | if (!node) | ||
1206 | continue; | ||
1207 | qn->qn_nodes[count].ni_nodenum = node->nd_num; | ||
1208 | qn->qn_nodes[count].ni_ipv4_port = node->nd_ipv4_port; | ||
1209 | qn->qn_nodes[count].ni_ipv4_address = node->nd_ipv4_address; | ||
1210 | mlog(0, "Node %3d, %pI4:%u\n", node->nd_num, | ||
1211 | &(node->nd_ipv4_address), ntohs(node->nd_ipv4_port)); | ||
1212 | ++count; | ||
1213 | o2nm_node_put(node); | ||
1214 | } | ||
1215 | |||
1216 | qn->qn_nodenum = dlm->node_num; | ||
1217 | qn->qn_numnodes = count; | ||
1218 | qn->qn_namelen = strlen(dlm->name); | ||
1219 | memcpy(qn->qn_domain, dlm->name, qn->qn_namelen); | ||
1220 | |||
1221 | i = -1; | ||
1222 | while ((i = find_next_bit(node_map, O2NM_MAX_NODES, | ||
1223 | i + 1)) < O2NM_MAX_NODES) { | ||
1224 | if (i == dlm->node_num) | ||
1225 | continue; | ||
1226 | |||
1227 | mlog(0, "Sending nodeinfo to node %d\n", i); | ||
1228 | |||
1229 | ret = o2net_send_message(DLM_QUERY_NODEINFO, DLM_MOD_KEY, | ||
1230 | qn, sizeof(struct dlm_query_nodeinfo), | ||
1231 | i, &status); | ||
1232 | if (ret >= 0) | ||
1233 | ret = status; | ||
1234 | if (ret) { | ||
1235 | mlog(ML_ERROR, "node mismatch %d, node %d\n", ret, i); | ||
1236 | break; | ||
1237 | } | ||
1238 | } | ||
1239 | |||
1240 | bail: | ||
1241 | kfree(qn); | ||
1242 | return ret; | ||
1243 | } | ||
1244 | |||
1245 | static int dlm_query_nodeinfo_handler(struct o2net_msg *msg, u32 len, | ||
1246 | void *data, void **ret_data) | ||
1247 | { | ||
1248 | struct dlm_query_nodeinfo *qn; | ||
1249 | struct dlm_ctxt *dlm = NULL; | ||
1250 | int locked = 0, status = -EINVAL; | ||
1251 | |||
1252 | qn = (struct dlm_query_nodeinfo *) msg->buf; | ||
1253 | |||
1254 | mlog(0, "Node %u queries nodes on domain %s\n", qn->qn_nodenum, | ||
1255 | qn->qn_domain); | ||
1256 | |||
1257 | spin_lock(&dlm_domain_lock); | ||
1258 | dlm = __dlm_lookup_domain_full(qn->qn_domain, qn->qn_namelen); | ||
1259 | if (!dlm) { | ||
1260 | mlog(ML_ERROR, "Node %d queried nodes on domain %s before " | ||
1261 | "join domain\n", qn->qn_nodenum, qn->qn_domain); | ||
1262 | goto bail; | ||
1263 | } | ||
1264 | |||
1265 | spin_lock(&dlm->spinlock); | ||
1266 | locked = 1; | ||
1267 | if (dlm->joining_node != qn->qn_nodenum) { | ||
1268 | mlog(ML_ERROR, "Node %d queried nodes on domain %s but " | ||
1269 | "joining node is %d\n", qn->qn_nodenum, qn->qn_domain, | ||
1270 | dlm->joining_node); | ||
1271 | goto bail; | ||
1272 | } | ||
1273 | |||
1274 | /* Support for node query was added in 1.1 */ | ||
1275 | if (dlm->dlm_locking_proto.pv_major == 1 && | ||
1276 | dlm->dlm_locking_proto.pv_minor == 0) { | ||
1277 | mlog(ML_ERROR, "Node %d queried nodes on domain %s " | ||
1278 | "but active dlm protocol is %d.%d\n", qn->qn_nodenum, | ||
1279 | qn->qn_domain, dlm->dlm_locking_proto.pv_major, | ||
1280 | dlm->dlm_locking_proto.pv_minor); | ||
1281 | goto bail; | ||
1282 | } | ||
1283 | |||
1284 | status = dlm_match_nodes(dlm, qn); | ||
1285 | |||
1286 | bail: | ||
1287 | if (locked) | ||
1288 | spin_unlock(&dlm->spinlock); | ||
1289 | spin_unlock(&dlm_domain_lock); | ||
1290 | |||
1291 | return status; | ||
1292 | } | ||
1293 | |||
923 | static int dlm_cancel_join_handler(struct o2net_msg *msg, u32 len, void *data, | 1294 | static int dlm_cancel_join_handler(struct o2net_msg *msg, u32 len, void *data, |
924 | void **ret_data) | 1295 | void **ret_data) |
925 | { | 1296 | { |
@@ -1240,6 +1611,20 @@ static int dlm_try_to_join_domain(struct dlm_ctxt *dlm) | |||
1240 | set_bit(dlm->node_num, dlm->domain_map); | 1611 | set_bit(dlm->node_num, dlm->domain_map); |
1241 | spin_unlock(&dlm->spinlock); | 1612 | spin_unlock(&dlm->spinlock); |
1242 | 1613 | ||
1614 | /* Support for global heartbeat and node info was added in 1.1 */ | ||
1615 | if (dlm_protocol.pv_major > 1 || dlm_protocol.pv_minor > 0) { | ||
1616 | status = dlm_send_nodeinfo(dlm, ctxt->yes_resp_map); | ||
1617 | if (status) { | ||
1618 | mlog_errno(status); | ||
1619 | goto bail; | ||
1620 | } | ||
1621 | status = dlm_send_regions(dlm, ctxt->yes_resp_map); | ||
1622 | if (status) { | ||
1623 | mlog_errno(status); | ||
1624 | goto bail; | ||
1625 | } | ||
1626 | } | ||
1627 | |||
1243 | dlm_send_join_asserts(dlm, ctxt->yes_resp_map); | 1628 | dlm_send_join_asserts(dlm, ctxt->yes_resp_map); |
1244 | 1629 | ||
1245 | /* Joined state *must* be set before the joining node | 1630 | /* Joined state *must* be set before the joining node |
@@ -1806,7 +2191,21 @@ static int dlm_register_net_handlers(void) | |||
1806 | sizeof(struct dlm_cancel_join), | 2191 | sizeof(struct dlm_cancel_join), |
1807 | dlm_cancel_join_handler, | 2192 | dlm_cancel_join_handler, |
1808 | NULL, NULL, &dlm_join_handlers); | 2193 | NULL, NULL, &dlm_join_handlers); |
2194 | if (status) | ||
2195 | goto bail; | ||
2196 | |||
2197 | status = o2net_register_handler(DLM_QUERY_REGION, DLM_MOD_KEY, | ||
2198 | sizeof(struct dlm_query_region), | ||
2199 | dlm_query_region_handler, | ||
2200 | NULL, NULL, &dlm_join_handlers); | ||
1809 | 2201 | ||
2202 | if (status) | ||
2203 | goto bail; | ||
2204 | |||
2205 | status = o2net_register_handler(DLM_QUERY_NODEINFO, DLM_MOD_KEY, | ||
2206 | sizeof(struct dlm_query_nodeinfo), | ||
2207 | dlm_query_nodeinfo_handler, | ||
2208 | NULL, NULL, &dlm_join_handlers); | ||
1810 | bail: | 2209 | bail: |
1811 | if (status < 0) | 2210 | if (status < 0) |
1812 | dlm_unregister_net_handlers(); | 2211 | dlm_unregister_net_handlers(); |
diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c index ffb4c68dafa4..f564b0e5f80d 100644 --- a/fs/ocfs2/dlm/dlmmaster.c +++ b/fs/ocfs2/dlm/dlmmaster.c | |||
@@ -3433,3 +3433,43 @@ void dlm_lockres_release_ast(struct dlm_ctxt *dlm, | |||
3433 | wake_up(&res->wq); | 3433 | wake_up(&res->wq); |
3434 | wake_up(&dlm->migration_wq); | 3434 | wake_up(&dlm->migration_wq); |
3435 | } | 3435 | } |
3436 | |||
3437 | void dlm_force_free_mles(struct dlm_ctxt *dlm) | ||
3438 | { | ||
3439 | int i; | ||
3440 | struct hlist_head *bucket; | ||
3441 | struct dlm_master_list_entry *mle; | ||
3442 | struct hlist_node *tmp, *list; | ||
3443 | |||
3444 | /* | ||
3445 | * We notified all other nodes that we are exiting the domain and | ||
3446 | * marked the dlm state to DLM_CTXT_LEAVING. If any mles are still | ||
3447 | * around we force free them and wake any processes that are waiting | ||
3448 | * on the mles | ||
3449 | */ | ||
3450 | spin_lock(&dlm->spinlock); | ||
3451 | spin_lock(&dlm->master_lock); | ||
3452 | |||
3453 | BUG_ON(dlm->dlm_state != DLM_CTXT_LEAVING); | ||
3454 | BUG_ON((find_next_bit(dlm->domain_map, O2NM_MAX_NODES, 0) < O2NM_MAX_NODES)); | ||
3455 | |||
3456 | for (i = 0; i < DLM_HASH_BUCKETS; i++) { | ||
3457 | bucket = dlm_master_hash(dlm, i); | ||
3458 | hlist_for_each_safe(list, tmp, bucket) { | ||
3459 | mle = hlist_entry(list, struct dlm_master_list_entry, | ||
3460 | master_hash_node); | ||
3461 | if (mle->type != DLM_MLE_BLOCK) { | ||
3462 | mlog(ML_ERROR, "bad mle: %p\n", mle); | ||
3463 | dlm_print_one_mle(mle); | ||
3464 | } | ||
3465 | atomic_set(&mle->woken, 1); | ||
3466 | wake_up(&mle->wq); | ||
3467 | |||
3468 | __dlm_unlink_mle(dlm, mle); | ||
3469 | __dlm_mle_detach_hb_events(dlm, mle); | ||
3470 | __dlm_put_mle(mle); | ||
3471 | } | ||
3472 | } | ||
3473 | spin_unlock(&dlm->master_lock); | ||
3474 | spin_unlock(&dlm->spinlock); | ||
3475 | } | ||
diff --git a/fs/ocfs2/dlmglue.h b/fs/ocfs2/dlmglue.h index d1ce48e1b3d6..1d596d8c4a4a 100644 --- a/fs/ocfs2/dlmglue.h +++ b/fs/ocfs2/dlmglue.h | |||
@@ -84,6 +84,7 @@ enum { | |||
84 | OI_LS_PARENT, | 84 | OI_LS_PARENT, |
85 | OI_LS_RENAME1, | 85 | OI_LS_RENAME1, |
86 | OI_LS_RENAME2, | 86 | OI_LS_RENAME2, |
87 | OI_LS_REFLINK_TARGET, | ||
87 | }; | 88 | }; |
88 | 89 | ||
89 | int ocfs2_dlm_init(struct ocfs2_super *osb); | 90 | int ocfs2_dlm_init(struct ocfs2_super *osb); |
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index 3064feef1430..d8408217e3bd 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h | |||
@@ -250,7 +250,7 @@ enum ocfs2_local_alloc_state | |||
250 | 250 | ||
251 | enum ocfs2_mount_options | 251 | enum ocfs2_mount_options |
252 | { | 252 | { |
253 | OCFS2_MOUNT_HB_LOCAL = 1 << 0, /* Heartbeat started in local mode */ | 253 | OCFS2_MOUNT_HB_LOCAL = 1 << 0, /* Local heartbeat */ |
254 | OCFS2_MOUNT_BARRIER = 1 << 1, /* Use block barriers */ | 254 | OCFS2_MOUNT_BARRIER = 1 << 1, /* Use block barriers */ |
255 | OCFS2_MOUNT_NOINTR = 1 << 2, /* Don't catch signals */ | 255 | OCFS2_MOUNT_NOINTR = 1 << 2, /* Don't catch signals */ |
256 | OCFS2_MOUNT_ERRORS_PANIC = 1 << 3, /* Panic on errors */ | 256 | OCFS2_MOUNT_ERRORS_PANIC = 1 << 3, /* Panic on errors */ |
@@ -263,9 +263,10 @@ enum ocfs2_mount_options | |||
263 | control lists */ | 263 | control lists */ |
264 | OCFS2_MOUNT_USRQUOTA = 1 << 10, /* We support user quotas */ | 264 | OCFS2_MOUNT_USRQUOTA = 1 << 10, /* We support user quotas */ |
265 | OCFS2_MOUNT_GRPQUOTA = 1 << 11, /* We support group quotas */ | 265 | OCFS2_MOUNT_GRPQUOTA = 1 << 11, /* We support group quotas */ |
266 | 266 | OCFS2_MOUNT_COHERENCY_BUFFERED = 1 << 12, /* Allow concurrent O_DIRECT | |
267 | OCFS2_MOUNT_COHERENCY_BUFFERED = 1 << 12 /* Allow concurrent O_DIRECT | 267 | writes */ |
268 | writes */ | 268 | OCFS2_MOUNT_HB_NONE = 1 << 13, /* No heartbeat */ |
269 | OCFS2_MOUNT_HB_GLOBAL = 1 << 14, /* Global heartbeat */ | ||
269 | }; | 270 | }; |
270 | 271 | ||
271 | #define OCFS2_OSB_SOFT_RO 0x0001 | 272 | #define OCFS2_OSB_SOFT_RO 0x0001 |
@@ -379,6 +380,8 @@ struct ocfs2_super | |||
379 | struct ocfs2_alloc_stats alloc_stats; | 380 | struct ocfs2_alloc_stats alloc_stats; |
380 | char dev_str[20]; /* "major,minor" of the device */ | 381 | char dev_str[20]; /* "major,minor" of the device */ |
381 | 382 | ||
383 | u8 osb_stackflags; | ||
384 | |||
382 | char osb_cluster_stack[OCFS2_STACK_LABEL_LEN + 1]; | 385 | char osb_cluster_stack[OCFS2_STACK_LABEL_LEN + 1]; |
383 | struct ocfs2_cluster_connection *cconn; | 386 | struct ocfs2_cluster_connection *cconn; |
384 | struct ocfs2_lock_res osb_super_lockres; | 387 | struct ocfs2_lock_res osb_super_lockres; |
@@ -612,10 +615,35 @@ static inline int ocfs2_is_soft_readonly(struct ocfs2_super *osb) | |||
612 | return ret; | 615 | return ret; |
613 | } | 616 | } |
614 | 617 | ||
615 | static inline int ocfs2_userspace_stack(struct ocfs2_super *osb) | 618 | static inline int ocfs2_clusterinfo_valid(struct ocfs2_super *osb) |
616 | { | 619 | { |
617 | return (osb->s_feature_incompat & | 620 | return (osb->s_feature_incompat & |
618 | OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK); | 621 | (OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK | |
622 | OCFS2_FEATURE_INCOMPAT_CLUSTERINFO)); | ||
623 | } | ||
624 | |||
625 | static inline int ocfs2_userspace_stack(struct ocfs2_super *osb) | ||
626 | { | ||
627 | if (ocfs2_clusterinfo_valid(osb) && | ||
628 | memcmp(osb->osb_cluster_stack, OCFS2_CLASSIC_CLUSTER_STACK, | ||
629 | OCFS2_STACK_LABEL_LEN)) | ||
630 | return 1; | ||
631 | return 0; | ||
632 | } | ||
633 | |||
634 | static inline int ocfs2_o2cb_stack(struct ocfs2_super *osb) | ||
635 | { | ||
636 | if (ocfs2_clusterinfo_valid(osb) && | ||
637 | !memcmp(osb->osb_cluster_stack, OCFS2_CLASSIC_CLUSTER_STACK, | ||
638 | OCFS2_STACK_LABEL_LEN)) | ||
639 | return 1; | ||
640 | return 0; | ||
641 | } | ||
642 | |||
643 | static inline int ocfs2_cluster_o2cb_global_heartbeat(struct ocfs2_super *osb) | ||
644 | { | ||
645 | return ocfs2_o2cb_stack(osb) && | ||
646 | (osb->osb_stackflags & OCFS2_CLUSTER_O2CB_GLOBAL_HEARTBEAT); | ||
619 | } | 647 | } |
620 | 648 | ||
621 | static inline int ocfs2_mount_local(struct ocfs2_super *osb) | 649 | static inline int ocfs2_mount_local(struct ocfs2_super *osb) |
diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h index 723b20dac414..c2e4f8222e2f 100644 --- a/fs/ocfs2/ocfs2_fs.h +++ b/fs/ocfs2/ocfs2_fs.h | |||
@@ -101,7 +101,8 @@ | |||
101 | | OCFS2_FEATURE_INCOMPAT_META_ECC \ | 101 | | OCFS2_FEATURE_INCOMPAT_META_ECC \ |
102 | | OCFS2_FEATURE_INCOMPAT_INDEXED_DIRS \ | 102 | | OCFS2_FEATURE_INCOMPAT_INDEXED_DIRS \ |
103 | | OCFS2_FEATURE_INCOMPAT_REFCOUNT_TREE \ | 103 | | OCFS2_FEATURE_INCOMPAT_REFCOUNT_TREE \ |
104 | | OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG) | 104 | | OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG \ |
105 | | OCFS2_FEATURE_INCOMPAT_CLUSTERINFO) | ||
105 | #define OCFS2_FEATURE_RO_COMPAT_SUPP (OCFS2_FEATURE_RO_COMPAT_UNWRITTEN \ | 106 | #define OCFS2_FEATURE_RO_COMPAT_SUPP (OCFS2_FEATURE_RO_COMPAT_UNWRITTEN \ |
106 | | OCFS2_FEATURE_RO_COMPAT_USRQUOTA \ | 107 | | OCFS2_FEATURE_RO_COMPAT_USRQUOTA \ |
107 | | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA) | 108 | | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA) |
@@ -170,6 +171,13 @@ | |||
170 | #define OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG 0x2000 | 171 | #define OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG 0x2000 |
171 | 172 | ||
172 | /* | 173 | /* |
174 | * Incompat bit to indicate useable clusterinfo with stackflags for all | ||
175 | * cluster stacks (userspace adnd o2cb). If this bit is set, | ||
176 | * INCOMPAT_USERSPACE_STACK becomes superfluous and thus should not be set. | ||
177 | */ | ||
178 | #define OCFS2_FEATURE_INCOMPAT_CLUSTERINFO 0x4000 | ||
179 | |||
180 | /* | ||
173 | * backup superblock flag is used to indicate that this volume | 181 | * backup superblock flag is used to indicate that this volume |
174 | * has backup superblocks. | 182 | * has backup superblocks. |
175 | */ | 183 | */ |
@@ -235,18 +243,31 @@ | |||
235 | #define OCFS2_HAS_REFCOUNT_FL (0x0010) | 243 | #define OCFS2_HAS_REFCOUNT_FL (0x0010) |
236 | 244 | ||
237 | /* Inode attributes, keep in sync with EXT2 */ | 245 | /* Inode attributes, keep in sync with EXT2 */ |
238 | #define OCFS2_SECRM_FL (0x00000001) /* Secure deletion */ | 246 | #define OCFS2_SECRM_FL FS_SECRM_FL /* Secure deletion */ |
239 | #define OCFS2_UNRM_FL (0x00000002) /* Undelete */ | 247 | #define OCFS2_UNRM_FL FS_UNRM_FL /* Undelete */ |
240 | #define OCFS2_COMPR_FL (0x00000004) /* Compress file */ | 248 | #define OCFS2_COMPR_FL FS_COMPR_FL /* Compress file */ |
241 | #define OCFS2_SYNC_FL (0x00000008) /* Synchronous updates */ | 249 | #define OCFS2_SYNC_FL FS_SYNC_FL /* Synchronous updates */ |
242 | #define OCFS2_IMMUTABLE_FL (0x00000010) /* Immutable file */ | 250 | #define OCFS2_IMMUTABLE_FL FS_IMMUTABLE_FL /* Immutable file */ |
243 | #define OCFS2_APPEND_FL (0x00000020) /* writes to file may only append */ | 251 | #define OCFS2_APPEND_FL FS_APPEND_FL /* writes to file may only append */ |
244 | #define OCFS2_NODUMP_FL (0x00000040) /* do not dump file */ | 252 | #define OCFS2_NODUMP_FL FS_NODUMP_FL /* do not dump file */ |
245 | #define OCFS2_NOATIME_FL (0x00000080) /* do not update atime */ | 253 | #define OCFS2_NOATIME_FL FS_NOATIME_FL /* do not update atime */ |
246 | #define OCFS2_DIRSYNC_FL (0x00010000) /* dirsync behaviour (directories only) */ | 254 | /* Reserved for compression usage... */ |
247 | 255 | #define OCFS2_DIRTY_FL FS_DIRTY_FL | |
248 | #define OCFS2_FL_VISIBLE (0x000100FF) /* User visible flags */ | 256 | #define OCFS2_COMPRBLK_FL FS_COMPRBLK_FL /* One or more compressed clusters */ |
249 | #define OCFS2_FL_MODIFIABLE (0x000100FF) /* User modifiable flags */ | 257 | #define OCFS2_NOCOMP_FL FS_NOCOMP_FL /* Don't compress */ |
258 | #define OCFS2_ECOMPR_FL FS_ECOMPR_FL /* Compression error */ | ||
259 | /* End compression flags --- maybe not all used */ | ||
260 | #define OCFS2_BTREE_FL FS_BTREE_FL /* btree format dir */ | ||
261 | #define OCFS2_INDEX_FL FS_INDEX_FL /* hash-indexed directory */ | ||
262 | #define OCFS2_IMAGIC_FL FS_IMAGIC_FL /* AFS directory */ | ||
263 | #define OCFS2_JOURNAL_DATA_FL FS_JOURNAL_DATA_FL /* Reserved for ext3 */ | ||
264 | #define OCFS2_NOTAIL_FL FS_NOTAIL_FL /* file tail should not be merged */ | ||
265 | #define OCFS2_DIRSYNC_FL FS_DIRSYNC_FL /* dirsync behaviour (directories only) */ | ||
266 | #define OCFS2_TOPDIR_FL FS_TOPDIR_FL /* Top of directory hierarchies*/ | ||
267 | #define OCFS2_RESERVED_FL FS_RESERVED_FL /* reserved for ext2 lib */ | ||
268 | |||
269 | #define OCFS2_FL_VISIBLE FS_FL_USER_VISIBLE /* User visible flags */ | ||
270 | #define OCFS2_FL_MODIFIABLE FS_FL_USER_MODIFIABLE /* User modifiable flags */ | ||
250 | 271 | ||
251 | /* | 272 | /* |
252 | * Extent record flags (e_node.leaf.flags) | 273 | * Extent record flags (e_node.leaf.flags) |
@@ -279,10 +300,13 @@ | |||
279 | #define OCFS2_VOL_UUID_LEN 16 | 300 | #define OCFS2_VOL_UUID_LEN 16 |
280 | #define OCFS2_MAX_VOL_LABEL_LEN 64 | 301 | #define OCFS2_MAX_VOL_LABEL_LEN 64 |
281 | 302 | ||
282 | /* The alternate, userspace stack fields */ | 303 | /* The cluster stack fields */ |
283 | #define OCFS2_STACK_LABEL_LEN 4 | 304 | #define OCFS2_STACK_LABEL_LEN 4 |
284 | #define OCFS2_CLUSTER_NAME_LEN 16 | 305 | #define OCFS2_CLUSTER_NAME_LEN 16 |
285 | 306 | ||
307 | /* Classic (historically speaking) cluster stack */ | ||
308 | #define OCFS2_CLASSIC_CLUSTER_STACK "o2cb" | ||
309 | |||
286 | /* Journal limits (in bytes) */ | 310 | /* Journal limits (in bytes) */ |
287 | #define OCFS2_MIN_JOURNAL_SIZE (4 * 1024 * 1024) | 311 | #define OCFS2_MIN_JOURNAL_SIZE (4 * 1024 * 1024) |
288 | 312 | ||
@@ -292,6 +316,11 @@ | |||
292 | */ | 316 | */ |
293 | #define OCFS2_MIN_XATTR_INLINE_SIZE 256 | 317 | #define OCFS2_MIN_XATTR_INLINE_SIZE 256 |
294 | 318 | ||
319 | /* | ||
320 | * Cluster info flags (ocfs2_cluster_info.ci_stackflags) | ||
321 | */ | ||
322 | #define OCFS2_CLUSTER_O2CB_GLOBAL_HEARTBEAT (0x01) | ||
323 | |||
295 | struct ocfs2_system_inode_info { | 324 | struct ocfs2_system_inode_info { |
296 | char *si_name; | 325 | char *si_name; |
297 | int si_iflags; | 326 | int si_iflags; |
@@ -352,6 +381,7 @@ static struct ocfs2_system_inode_info ocfs2_system_inodes[NUM_SYSTEM_INODES] = { | |||
352 | /* Parameter passed from mount.ocfs2 to module */ | 381 | /* Parameter passed from mount.ocfs2 to module */ |
353 | #define OCFS2_HB_NONE "heartbeat=none" | 382 | #define OCFS2_HB_NONE "heartbeat=none" |
354 | #define OCFS2_HB_LOCAL "heartbeat=local" | 383 | #define OCFS2_HB_LOCAL "heartbeat=local" |
384 | #define OCFS2_HB_GLOBAL "heartbeat=global" | ||
355 | 385 | ||
356 | /* | 386 | /* |
357 | * OCFS2 directory file types. Only the low 3 bits are used. The | 387 | * OCFS2 directory file types. Only the low 3 bits are used. The |
@@ -558,9 +588,21 @@ struct ocfs2_slot_map_extended { | |||
558 | */ | 588 | */ |
559 | }; | 589 | }; |
560 | 590 | ||
591 | /* | ||
592 | * ci_stackflags is only valid if the incompat bit | ||
593 | * OCFS2_FEATURE_INCOMPAT_CLUSTERINFO is set. | ||
594 | */ | ||
561 | struct ocfs2_cluster_info { | 595 | struct ocfs2_cluster_info { |
562 | /*00*/ __u8 ci_stack[OCFS2_STACK_LABEL_LEN]; | 596 | /*00*/ __u8 ci_stack[OCFS2_STACK_LABEL_LEN]; |
563 | __le32 ci_reserved; | 597 | union { |
598 | __le32 ci_reserved; | ||
599 | struct { | ||
600 | __u8 ci_stackflags; | ||
601 | __u8 ci_reserved1; | ||
602 | __u8 ci_reserved2; | ||
603 | __u8 ci_reserved3; | ||
604 | }; | ||
605 | }; | ||
564 | /*08*/ __u8 ci_cluster[OCFS2_CLUSTER_NAME_LEN]; | 606 | /*08*/ __u8 ci_cluster[OCFS2_CLUSTER_NAME_LEN]; |
565 | /*18*/ | 607 | /*18*/ |
566 | }; | 608 | }; |
@@ -597,9 +639,9 @@ struct ocfs2_super_block { | |||
597 | * group header */ | 639 | * group header */ |
598 | /*50*/ __u8 s_label[OCFS2_MAX_VOL_LABEL_LEN]; /* Label for mounting, etc. */ | 640 | /*50*/ __u8 s_label[OCFS2_MAX_VOL_LABEL_LEN]; /* Label for mounting, etc. */ |
599 | /*90*/ __u8 s_uuid[OCFS2_VOL_UUID_LEN]; /* 128-bit uuid */ | 641 | /*90*/ __u8 s_uuid[OCFS2_VOL_UUID_LEN]; /* 128-bit uuid */ |
600 | /*A0*/ struct ocfs2_cluster_info s_cluster_info; /* Selected userspace | 642 | /*A0*/ struct ocfs2_cluster_info s_cluster_info; /* Only valid if either |
601 | stack. Only valid | 643 | userspace or clusterinfo |
602 | with INCOMPAT flag. */ | 644 | INCOMPAT flag set. */ |
603 | /*B8*/ __le16 s_xattr_inline_size; /* extended attribute inline size | 645 | /*B8*/ __le16 s_xattr_inline_size; /* extended attribute inline size |
604 | for this fs*/ | 646 | for this fs*/ |
605 | __le16 s_reserved0; | 647 | __le16 s_reserved0; |
diff --git a/fs/ocfs2/ocfs2_ioctl.h b/fs/ocfs2/ocfs2_ioctl.h index 9bc535499868..b46f39bf7438 100644 --- a/fs/ocfs2/ocfs2_ioctl.h +++ b/fs/ocfs2/ocfs2_ioctl.h | |||
@@ -23,10 +23,10 @@ | |||
23 | /* | 23 | /* |
24 | * ioctl commands | 24 | * ioctl commands |
25 | */ | 25 | */ |
26 | #define OCFS2_IOC_GETFLAGS _IOR('f', 1, long) | 26 | #define OCFS2_IOC_GETFLAGS FS_IOC_GETFLAGS |
27 | #define OCFS2_IOC_SETFLAGS _IOW('f', 2, long) | 27 | #define OCFS2_IOC_SETFLAGS FS_IOC_SETFLAGS |
28 | #define OCFS2_IOC32_GETFLAGS _IOR('f', 1, int) | 28 | #define OCFS2_IOC32_GETFLAGS FS_IOC32_GETFLAGS |
29 | #define OCFS2_IOC32_SETFLAGS _IOW('f', 2, int) | 29 | #define OCFS2_IOC32_SETFLAGS FS_IOC32_SETFLAGS |
30 | 30 | ||
31 | /* | 31 | /* |
32 | * Space reservation / allocation / free ioctls and argument structure | 32 | * Space reservation / allocation / free ioctls and argument structure |
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index a120cfcf69bf..b5f9160e93e9 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c | |||
@@ -4240,8 +4240,9 @@ static int __ocfs2_reflink(struct dentry *old_dentry, | |||
4240 | goto out; | 4240 | goto out; |
4241 | } | 4241 | } |
4242 | 4242 | ||
4243 | mutex_lock(&new_inode->i_mutex); | 4243 | mutex_lock_nested(&new_inode->i_mutex, I_MUTEX_CHILD); |
4244 | ret = ocfs2_inode_lock(new_inode, &new_bh, 1); | 4244 | ret = ocfs2_inode_lock_nested(new_inode, &new_bh, 1, |
4245 | OI_LS_REFLINK_TARGET); | ||
4245 | if (ret) { | 4246 | if (ret) { |
4246 | mlog_errno(ret); | 4247 | mlog_errno(ret); |
4247 | goto out_unlock; | 4248 | goto out_unlock; |
diff --git a/fs/ocfs2/reservations.c b/fs/ocfs2/reservations.c index d8b6e4259b80..3e78db361bc7 100644 --- a/fs/ocfs2/reservations.c +++ b/fs/ocfs2/reservations.c | |||
@@ -732,25 +732,23 @@ int ocfs2_resmap_resv_bits(struct ocfs2_reservation_map *resmap, | |||
732 | struct ocfs2_alloc_reservation *resv, | 732 | struct ocfs2_alloc_reservation *resv, |
733 | int *cstart, int *clen) | 733 | int *cstart, int *clen) |
734 | { | 734 | { |
735 | unsigned int wanted = *clen; | ||
736 | |||
737 | if (resv == NULL || ocfs2_resmap_disabled(resmap)) | 735 | if (resv == NULL || ocfs2_resmap_disabled(resmap)) |
738 | return -ENOSPC; | 736 | return -ENOSPC; |
739 | 737 | ||
740 | spin_lock(&resv_lock); | 738 | spin_lock(&resv_lock); |
741 | 739 | ||
742 | /* | ||
743 | * We don't want to over-allocate for temporary | ||
744 | * windows. Otherwise, we run the risk of fragmenting the | ||
745 | * allocation space. | ||
746 | */ | ||
747 | wanted = ocfs2_resv_window_bits(resmap, resv); | ||
748 | if ((resv->r_flags & OCFS2_RESV_FLAG_TMP) || wanted < *clen) | ||
749 | wanted = *clen; | ||
750 | |||
751 | if (ocfs2_resv_empty(resv)) { | 740 | if (ocfs2_resv_empty(resv)) { |
752 | mlog(0, "empty reservation, find new window\n"); | 741 | /* |
742 | * We don't want to over-allocate for temporary | ||
743 | * windows. Otherwise, we run the risk of fragmenting the | ||
744 | * allocation space. | ||
745 | */ | ||
746 | unsigned int wanted = ocfs2_resv_window_bits(resmap, resv); | ||
753 | 747 | ||
748 | if ((resv->r_flags & OCFS2_RESV_FLAG_TMP) || wanted < *clen) | ||
749 | wanted = *clen; | ||
750 | |||
751 | mlog(0, "empty reservation, find new window\n"); | ||
754 | /* | 752 | /* |
755 | * Try to get a window here. If it works, we must fall | 753 | * Try to get a window here. If it works, we must fall |
756 | * through and test the bitmap . This avoids some | 754 | * through and test the bitmap . This avoids some |
diff --git a/fs/ocfs2/stack_o2cb.c b/fs/ocfs2/stack_o2cb.c index 0d3049f696c5..19965b00c43c 100644 --- a/fs/ocfs2/stack_o2cb.c +++ b/fs/ocfs2/stack_o2cb.c | |||
@@ -283,6 +283,8 @@ static int o2cb_cluster_connect(struct ocfs2_cluster_connection *conn) | |||
283 | /* for now we only have one cluster/node, make sure we see it | 283 | /* for now we only have one cluster/node, make sure we see it |
284 | * in the heartbeat universe */ | 284 | * in the heartbeat universe */ |
285 | if (!o2hb_check_local_node_heartbeating()) { | 285 | if (!o2hb_check_local_node_heartbeating()) { |
286 | if (o2hb_global_heartbeat_active()) | ||
287 | mlog(ML_ERROR, "Global heartbeat not started\n"); | ||
286 | rc = -EINVAL; | 288 | rc = -EINVAL; |
287 | goto out; | 289 | goto out; |
288 | } | 290 | } |
diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index 64f2c50a1c37..5fed60de7630 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c | |||
@@ -357,7 +357,7 @@ out: | |||
357 | static void ocfs2_bg_discontig_add_extent(struct ocfs2_super *osb, | 357 | static void ocfs2_bg_discontig_add_extent(struct ocfs2_super *osb, |
358 | struct ocfs2_group_desc *bg, | 358 | struct ocfs2_group_desc *bg, |
359 | struct ocfs2_chain_list *cl, | 359 | struct ocfs2_chain_list *cl, |
360 | u64 p_blkno, u32 clusters) | 360 | u64 p_blkno, unsigned int clusters) |
361 | { | 361 | { |
362 | struct ocfs2_extent_list *el = &bg->bg_list; | 362 | struct ocfs2_extent_list *el = &bg->bg_list; |
363 | struct ocfs2_extent_rec *rec; | 363 | struct ocfs2_extent_rec *rec; |
@@ -369,7 +369,7 @@ static void ocfs2_bg_discontig_add_extent(struct ocfs2_super *osb, | |||
369 | rec->e_blkno = cpu_to_le64(p_blkno); | 369 | rec->e_blkno = cpu_to_le64(p_blkno); |
370 | rec->e_cpos = cpu_to_le32(le16_to_cpu(bg->bg_bits) / | 370 | rec->e_cpos = cpu_to_le32(le16_to_cpu(bg->bg_bits) / |
371 | le16_to_cpu(cl->cl_bpc)); | 371 | le16_to_cpu(cl->cl_bpc)); |
372 | rec->e_leaf_clusters = cpu_to_le32(clusters); | 372 | rec->e_leaf_clusters = cpu_to_le16(clusters); |
373 | le16_add_cpu(&bg->bg_bits, clusters * le16_to_cpu(cl->cl_bpc)); | 373 | le16_add_cpu(&bg->bg_bits, clusters * le16_to_cpu(cl->cl_bpc)); |
374 | le16_add_cpu(&bg->bg_free_bits_count, | 374 | le16_add_cpu(&bg->bg_free_bits_count, |
375 | clusters * le16_to_cpu(cl->cl_bpc)); | 375 | clusters * le16_to_cpu(cl->cl_bpc)); |
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 9122d59f8127..a8a0ca44f88f 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c | |||
@@ -162,6 +162,7 @@ enum { | |||
162 | Opt_nointr, | 162 | Opt_nointr, |
163 | Opt_hb_none, | 163 | Opt_hb_none, |
164 | Opt_hb_local, | 164 | Opt_hb_local, |
165 | Opt_hb_global, | ||
165 | Opt_data_ordered, | 166 | Opt_data_ordered, |
166 | Opt_data_writeback, | 167 | Opt_data_writeback, |
167 | Opt_atime_quantum, | 168 | Opt_atime_quantum, |
@@ -192,6 +193,7 @@ static const match_table_t tokens = { | |||
192 | {Opt_nointr, "nointr"}, | 193 | {Opt_nointr, "nointr"}, |
193 | {Opt_hb_none, OCFS2_HB_NONE}, | 194 | {Opt_hb_none, OCFS2_HB_NONE}, |
194 | {Opt_hb_local, OCFS2_HB_LOCAL}, | 195 | {Opt_hb_local, OCFS2_HB_LOCAL}, |
196 | {Opt_hb_global, OCFS2_HB_GLOBAL}, | ||
195 | {Opt_data_ordered, "data=ordered"}, | 197 | {Opt_data_ordered, "data=ordered"}, |
196 | {Opt_data_writeback, "data=writeback"}, | 198 | {Opt_data_writeback, "data=writeback"}, |
197 | {Opt_atime_quantum, "atime_quantum=%u"}, | 199 | {Opt_atime_quantum, "atime_quantum=%u"}, |
@@ -626,6 +628,7 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data) | |||
626 | int ret = 0; | 628 | int ret = 0; |
627 | struct mount_options parsed_options; | 629 | struct mount_options parsed_options; |
628 | struct ocfs2_super *osb = OCFS2_SB(sb); | 630 | struct ocfs2_super *osb = OCFS2_SB(sb); |
631 | u32 tmp; | ||
629 | 632 | ||
630 | lock_kernel(); | 633 | lock_kernel(); |
631 | 634 | ||
@@ -635,8 +638,9 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data) | |||
635 | goto out; | 638 | goto out; |
636 | } | 639 | } |
637 | 640 | ||
638 | if ((osb->s_mount_opt & OCFS2_MOUNT_HB_LOCAL) != | 641 | tmp = OCFS2_MOUNT_HB_LOCAL | OCFS2_MOUNT_HB_GLOBAL | |
639 | (parsed_options.mount_opt & OCFS2_MOUNT_HB_LOCAL)) { | 642 | OCFS2_MOUNT_HB_NONE; |
643 | if ((osb->s_mount_opt & tmp) != (parsed_options.mount_opt & tmp)) { | ||
640 | ret = -EINVAL; | 644 | ret = -EINVAL; |
641 | mlog(ML_ERROR, "Cannot change heartbeat mode on remount\n"); | 645 | mlog(ML_ERROR, "Cannot change heartbeat mode on remount\n"); |
642 | goto out; | 646 | goto out; |
@@ -827,23 +831,29 @@ bail: | |||
827 | 831 | ||
828 | static int ocfs2_verify_heartbeat(struct ocfs2_super *osb) | 832 | static int ocfs2_verify_heartbeat(struct ocfs2_super *osb) |
829 | { | 833 | { |
830 | if (ocfs2_mount_local(osb)) { | 834 | u32 hb_enabled = OCFS2_MOUNT_HB_LOCAL | OCFS2_MOUNT_HB_GLOBAL; |
831 | if (osb->s_mount_opt & OCFS2_MOUNT_HB_LOCAL) { | 835 | |
836 | if (osb->s_mount_opt & hb_enabled) { | ||
837 | if (ocfs2_mount_local(osb)) { | ||
832 | mlog(ML_ERROR, "Cannot heartbeat on a locally " | 838 | mlog(ML_ERROR, "Cannot heartbeat on a locally " |
833 | "mounted device.\n"); | 839 | "mounted device.\n"); |
834 | return -EINVAL; | 840 | return -EINVAL; |
835 | } | 841 | } |
836 | } | 842 | if (ocfs2_userspace_stack(osb)) { |
837 | |||
838 | if (ocfs2_userspace_stack(osb)) { | ||
839 | if (osb->s_mount_opt & OCFS2_MOUNT_HB_LOCAL) { | ||
840 | mlog(ML_ERROR, "Userspace stack expected, but " | 843 | mlog(ML_ERROR, "Userspace stack expected, but " |
841 | "o2cb heartbeat arguments passed to mount\n"); | 844 | "o2cb heartbeat arguments passed to mount\n"); |
842 | return -EINVAL; | 845 | return -EINVAL; |
843 | } | 846 | } |
847 | if (((osb->s_mount_opt & OCFS2_MOUNT_HB_GLOBAL) && | ||
848 | !ocfs2_cluster_o2cb_global_heartbeat(osb)) || | ||
849 | ((osb->s_mount_opt & OCFS2_MOUNT_HB_LOCAL) && | ||
850 | ocfs2_cluster_o2cb_global_heartbeat(osb))) { | ||
851 | mlog(ML_ERROR, "Mismatching o2cb heartbeat modes\n"); | ||
852 | return -EINVAL; | ||
853 | } | ||
844 | } | 854 | } |
845 | 855 | ||
846 | if (!(osb->s_mount_opt & OCFS2_MOUNT_HB_LOCAL)) { | 856 | if (!(osb->s_mount_opt & hb_enabled)) { |
847 | if (!ocfs2_mount_local(osb) && !ocfs2_is_hard_readonly(osb) && | 857 | if (!ocfs2_mount_local(osb) && !ocfs2_is_hard_readonly(osb) && |
848 | !ocfs2_userspace_stack(osb)) { | 858 | !ocfs2_userspace_stack(osb)) { |
849 | mlog(ML_ERROR, "Heartbeat has to be started to mount " | 859 | mlog(ML_ERROR, "Heartbeat has to be started to mount " |
@@ -1309,6 +1319,7 @@ static int ocfs2_parse_options(struct super_block *sb, | |||
1309 | { | 1319 | { |
1310 | int status; | 1320 | int status; |
1311 | char *p; | 1321 | char *p; |
1322 | u32 tmp; | ||
1312 | 1323 | ||
1313 | mlog_entry("remount: %d, options: \"%s\"\n", is_remount, | 1324 | mlog_entry("remount: %d, options: \"%s\"\n", is_remount, |
1314 | options ? options : "(none)"); | 1325 | options ? options : "(none)"); |
@@ -1340,7 +1351,10 @@ static int ocfs2_parse_options(struct super_block *sb, | |||
1340 | mopt->mount_opt |= OCFS2_MOUNT_HB_LOCAL; | 1351 | mopt->mount_opt |= OCFS2_MOUNT_HB_LOCAL; |
1341 | break; | 1352 | break; |
1342 | case Opt_hb_none: | 1353 | case Opt_hb_none: |
1343 | mopt->mount_opt &= ~OCFS2_MOUNT_HB_LOCAL; | 1354 | mopt->mount_opt |= OCFS2_MOUNT_HB_NONE; |
1355 | break; | ||
1356 | case Opt_hb_global: | ||
1357 | mopt->mount_opt |= OCFS2_MOUNT_HB_GLOBAL; | ||
1344 | break; | 1358 | break; |
1345 | case Opt_barrier: | 1359 | case Opt_barrier: |
1346 | if (match_int(&args[0], &option)) { | 1360 | if (match_int(&args[0], &option)) { |
@@ -1501,6 +1515,15 @@ static int ocfs2_parse_options(struct super_block *sb, | |||
1501 | } | 1515 | } |
1502 | } | 1516 | } |
1503 | 1517 | ||
1518 | /* Ensure only one heartbeat mode */ | ||
1519 | tmp = mopt->mount_opt & (OCFS2_MOUNT_HB_LOCAL | OCFS2_MOUNT_HB_GLOBAL | | ||
1520 | OCFS2_MOUNT_HB_NONE); | ||
1521 | if (hweight32(tmp) != 1) { | ||
1522 | mlog(ML_ERROR, "Invalid heartbeat mount options\n"); | ||
1523 | status = 0; | ||
1524 | goto bail; | ||
1525 | } | ||
1526 | |||
1504 | status = 1; | 1527 | status = 1; |
1505 | 1528 | ||
1506 | bail: | 1529 | bail: |
@@ -1514,10 +1537,14 @@ static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt) | |||
1514 | unsigned long opts = osb->s_mount_opt; | 1537 | unsigned long opts = osb->s_mount_opt; |
1515 | unsigned int local_alloc_megs; | 1538 | unsigned int local_alloc_megs; |
1516 | 1539 | ||
1517 | if (opts & OCFS2_MOUNT_HB_LOCAL) | 1540 | if (opts & (OCFS2_MOUNT_HB_LOCAL | OCFS2_MOUNT_HB_GLOBAL)) { |
1518 | seq_printf(s, ",_netdev,heartbeat=local"); | 1541 | seq_printf(s, ",_netdev"); |
1519 | else | 1542 | if (opts & OCFS2_MOUNT_HB_LOCAL) |
1520 | seq_printf(s, ",heartbeat=none"); | 1543 | seq_printf(s, ",%s", OCFS2_HB_LOCAL); |
1544 | else | ||
1545 | seq_printf(s, ",%s", OCFS2_HB_GLOBAL); | ||
1546 | } else | ||
1547 | seq_printf(s, ",%s", OCFS2_HB_NONE); | ||
1521 | 1548 | ||
1522 | if (opts & OCFS2_MOUNT_NOINTR) | 1549 | if (opts & OCFS2_MOUNT_NOINTR) |
1523 | seq_printf(s, ",nointr"); | 1550 | seq_printf(s, ",nointr"); |
@@ -2209,7 +2236,9 @@ static int ocfs2_initialize_super(struct super_block *sb, | |||
2209 | goto bail; | 2236 | goto bail; |
2210 | } | 2237 | } |
2211 | 2238 | ||
2212 | if (ocfs2_userspace_stack(osb)) { | 2239 | if (ocfs2_clusterinfo_valid(osb)) { |
2240 | osb->osb_stackflags = | ||
2241 | OCFS2_RAW_SB(di)->s_cluster_info.ci_stackflags; | ||
2213 | memcpy(osb->osb_cluster_stack, | 2242 | memcpy(osb->osb_cluster_stack, |
2214 | OCFS2_RAW_SB(di)->s_cluster_info.ci_stack, | 2243 | OCFS2_RAW_SB(di)->s_cluster_info.ci_stack, |
2215 | OCFS2_STACK_LABEL_LEN); | 2244 | OCFS2_STACK_LABEL_LEN); |
diff --git a/fs/ocfs2/symlink.c b/fs/ocfs2/symlink.c index 32499d213fc4..9975457c981f 100644 --- a/fs/ocfs2/symlink.c +++ b/fs/ocfs2/symlink.c | |||
@@ -128,7 +128,7 @@ static void *ocfs2_fast_follow_link(struct dentry *dentry, | |||
128 | } | 128 | } |
129 | 129 | ||
130 | /* Fast symlinks can't be large */ | 130 | /* Fast symlinks can't be large */ |
131 | len = strlen(target); | 131 | len = strnlen(target, ocfs2_fast_symlink_chars(inode->i_sb)); |
132 | link = kzalloc(len + 1, GFP_NOFS); | 132 | link = kzalloc(len + 1, GFP_NOFS); |
133 | if (!link) { | 133 | if (!link) { |
134 | status = -ENOMEM; | 134 | status = -ENOMEM; |
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index d03469f61801..06fa5e77c40e 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c | |||
@@ -1286,13 +1286,11 @@ int ocfs2_xattr_get_nolock(struct inode *inode, | |||
1286 | xis.inode_bh = xbs.inode_bh = di_bh; | 1286 | xis.inode_bh = xbs.inode_bh = di_bh; |
1287 | di = (struct ocfs2_dinode *)di_bh->b_data; | 1287 | di = (struct ocfs2_dinode *)di_bh->b_data; |
1288 | 1288 | ||
1289 | down_read(&oi->ip_xattr_sem); | ||
1290 | ret = ocfs2_xattr_ibody_get(inode, name_index, name, buffer, | 1289 | ret = ocfs2_xattr_ibody_get(inode, name_index, name, buffer, |
1291 | buffer_size, &xis); | 1290 | buffer_size, &xis); |
1292 | if (ret == -ENODATA && di->i_xattr_loc) | 1291 | if (ret == -ENODATA && di->i_xattr_loc) |
1293 | ret = ocfs2_xattr_block_get(inode, name_index, name, buffer, | 1292 | ret = ocfs2_xattr_block_get(inode, name_index, name, buffer, |
1294 | buffer_size, &xbs); | 1293 | buffer_size, &xbs); |
1295 | up_read(&oi->ip_xattr_sem); | ||
1296 | 1294 | ||
1297 | return ret; | 1295 | return ret; |
1298 | } | 1296 | } |
@@ -1316,8 +1314,10 @@ static int ocfs2_xattr_get(struct inode *inode, | |||
1316 | mlog_errno(ret); | 1314 | mlog_errno(ret); |
1317 | return ret; | 1315 | return ret; |
1318 | } | 1316 | } |
1317 | down_read(&OCFS2_I(inode)->ip_xattr_sem); | ||
1319 | ret = ocfs2_xattr_get_nolock(inode, di_bh, name_index, | 1318 | ret = ocfs2_xattr_get_nolock(inode, di_bh, name_index, |
1320 | name, buffer, buffer_size); | 1319 | name, buffer, buffer_size); |
1320 | up_read(&OCFS2_I(inode)->ip_xattr_sem); | ||
1321 | 1321 | ||
1322 | ocfs2_inode_unlock(inode, 0); | 1322 | ocfs2_inode_unlock(inode, 0); |
1323 | 1323 | ||