diff options
-rw-r--r-- | fs/ocfs2/stack_user.c | 216 | ||||
-rw-r--r-- | fs/ocfs2/stackglue.c | 14 | ||||
-rw-r--r-- | fs/ocfs2/stackglue.h | 19 |
3 files changed, 243 insertions, 6 deletions
diff --git a/fs/ocfs2/stack_user.c b/fs/ocfs2/stack_user.c index de982c11e69b..7428663f9cbb 100644 --- a/fs/ocfs2/stack_user.c +++ b/fs/ocfs2/stack_user.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/reboot.h> | 24 | #include <linux/reboot.h> |
25 | #include <asm/uaccess.h> | 25 | #include <asm/uaccess.h> |
26 | 26 | ||
27 | #include "ocfs2.h" /* For struct ocfs2_lock_res */ | ||
27 | #include "stackglue.h" | 28 | #include "stackglue.h" |
28 | 29 | ||
29 | 30 | ||
@@ -152,6 +153,8 @@ union ocfs2_control_message { | |||
152 | struct ocfs2_control_message_down u_down; | 153 | struct ocfs2_control_message_down u_down; |
153 | }; | 154 | }; |
154 | 155 | ||
156 | static struct ocfs2_stack_plugin user_stack; | ||
157 | |||
155 | static atomic_t ocfs2_control_opened; | 158 | static atomic_t ocfs2_control_opened; |
156 | static int ocfs2_control_this_node = -1; | 159 | static int ocfs2_control_this_node = -1; |
157 | static struct ocfs2_protocol_version running_proto; | 160 | static struct ocfs2_protocol_version running_proto; |
@@ -344,6 +347,20 @@ out_unlock: | |||
344 | return rc; | 347 | return rc; |
345 | } | 348 | } |
346 | 349 | ||
350 | static int ocfs2_control_get_this_node(void) | ||
351 | { | ||
352 | int rc; | ||
353 | |||
354 | mutex_lock(&ocfs2_control_lock); | ||
355 | if (ocfs2_control_this_node < 0) | ||
356 | rc = -EINVAL; | ||
357 | else | ||
358 | rc = ocfs2_control_this_node; | ||
359 | mutex_unlock(&ocfs2_control_lock); | ||
360 | |||
361 | return rc; | ||
362 | } | ||
363 | |||
347 | static int ocfs2_control_do_setnode_msg(struct file *file, | 364 | static int ocfs2_control_do_setnode_msg(struct file *file, |
348 | struct ocfs2_control_message_setn *msg) | 365 | struct ocfs2_control_message_setn *msg) |
349 | { | 366 | { |
@@ -652,13 +669,210 @@ static void ocfs2_control_exit(void) | |||
652 | -rc); | 669 | -rc); |
653 | } | 670 | } |
654 | 671 | ||
672 | static struct dlm_lksb *fsdlm_astarg_to_lksb(void *astarg) | ||
673 | { | ||
674 | struct ocfs2_lock_res *res = astarg; | ||
675 | return &res->l_lksb.lksb_fsdlm; | ||
676 | } | ||
677 | |||
678 | static void fsdlm_lock_ast_wrapper(void *astarg) | ||
679 | { | ||
680 | struct dlm_lksb *lksb = fsdlm_astarg_to_lksb(astarg); | ||
681 | int status = lksb->sb_status; | ||
682 | |||
683 | BUG_ON(user_stack.sp_proto == NULL); | ||
684 | |||
685 | /* | ||
686 | * For now we're punting on the issue of other non-standard errors | ||
687 | * where we can't tell if the unlock_ast or lock_ast should be called. | ||
688 | * The main "other error" that's possible is EINVAL which means the | ||
689 | * function was called with invalid args, which shouldn't be possible | ||
690 | * since the caller here is under our control. Other non-standard | ||
691 | * errors probably fall into the same category, or otherwise are fatal | ||
692 | * which means we can't carry on anyway. | ||
693 | */ | ||
694 | |||
695 | if (status == -DLM_EUNLOCK || status == -DLM_ECANCEL) | ||
696 | user_stack.sp_proto->lp_unlock_ast(astarg, 0); | ||
697 | else | ||
698 | user_stack.sp_proto->lp_lock_ast(astarg); | ||
699 | } | ||
700 | |||
701 | static void fsdlm_blocking_ast_wrapper(void *astarg, int level) | ||
702 | { | ||
703 | BUG_ON(user_stack.sp_proto == NULL); | ||
704 | |||
705 | user_stack.sp_proto->lp_blocking_ast(astarg, level); | ||
706 | } | ||
707 | |||
708 | static int user_dlm_lock(struct ocfs2_cluster_connection *conn, | ||
709 | int mode, | ||
710 | union ocfs2_dlm_lksb *lksb, | ||
711 | u32 flags, | ||
712 | void *name, | ||
713 | unsigned int namelen, | ||
714 | void *astarg) | ||
715 | { | ||
716 | int ret; | ||
717 | |||
718 | if (!lksb->lksb_fsdlm.sb_lvbptr) | ||
719 | lksb->lksb_fsdlm.sb_lvbptr = (char *)lksb + | ||
720 | sizeof(struct dlm_lksb); | ||
721 | |||
722 | ret = dlm_lock(conn->cc_lockspace, mode, &lksb->lksb_fsdlm, | ||
723 | flags|DLM_LKF_NODLCKWT, name, namelen, 0, | ||
724 | fsdlm_lock_ast_wrapper, astarg, | ||
725 | fsdlm_blocking_ast_wrapper); | ||
726 | return ret; | ||
727 | } | ||
728 | |||
729 | static int user_dlm_unlock(struct ocfs2_cluster_connection *conn, | ||
730 | union ocfs2_dlm_lksb *lksb, | ||
731 | u32 flags, | ||
732 | void *astarg) | ||
733 | { | ||
734 | int ret; | ||
735 | |||
736 | ret = dlm_unlock(conn->cc_lockspace, lksb->lksb_fsdlm.sb_lkid, | ||
737 | flags, &lksb->lksb_fsdlm, astarg); | ||
738 | return ret; | ||
739 | } | ||
740 | |||
741 | static int user_dlm_lock_status(union ocfs2_dlm_lksb *lksb) | ||
742 | { | ||
743 | return lksb->lksb_fsdlm.sb_status; | ||
744 | } | ||
745 | |||
746 | static void *user_dlm_lvb(union ocfs2_dlm_lksb *lksb) | ||
747 | { | ||
748 | return (void *)(lksb->lksb_fsdlm.sb_lvbptr); | ||
749 | } | ||
750 | |||
751 | static void user_dlm_dump_lksb(union ocfs2_dlm_lksb *lksb) | ||
752 | { | ||
753 | } | ||
754 | |||
755 | /* | ||
756 | * Compare a requested locking protocol version against the current one. | ||
757 | * | ||
758 | * If the major numbers are different, they are incompatible. | ||
759 | * If the current minor is greater than the request, they are incompatible. | ||
760 | * If the current minor is less than or equal to the request, they are | ||
761 | * compatible, and the requester should run at the current minor version. | ||
762 | */ | ||
763 | static int fs_protocol_compare(struct ocfs2_protocol_version *existing, | ||
764 | struct ocfs2_protocol_version *request) | ||
765 | { | ||
766 | if (existing->pv_major != request->pv_major) | ||
767 | return 1; | ||
768 | |||
769 | if (existing->pv_minor > request->pv_minor) | ||
770 | return 1; | ||
771 | |||
772 | if (existing->pv_minor < request->pv_minor) | ||
773 | request->pv_minor = existing->pv_minor; | ||
774 | |||
775 | return 0; | ||
776 | } | ||
777 | |||
778 | static int user_cluster_connect(struct ocfs2_cluster_connection *conn) | ||
779 | { | ||
780 | dlm_lockspace_t *fsdlm; | ||
781 | struct ocfs2_live_connection *control; | ||
782 | int rc = 0; | ||
783 | |||
784 | BUG_ON(conn == NULL); | ||
785 | |||
786 | rc = ocfs2_live_connection_new(conn, &control); | ||
787 | if (rc) | ||
788 | goto out; | ||
789 | |||
790 | /* | ||
791 | * running_proto must have been set before we allowed any mounts | ||
792 | * to proceed. | ||
793 | */ | ||
794 | if (fs_protocol_compare(&running_proto, &conn->cc_version)) { | ||
795 | printk(KERN_ERR | ||
796 | "Unable to mount with fs locking protocol version " | ||
797 | "%u.%u because the userspace control daemon has " | ||
798 | "negotiated %u.%u\n", | ||
799 | conn->cc_version.pv_major, conn->cc_version.pv_minor, | ||
800 | running_proto.pv_major, running_proto.pv_minor); | ||
801 | rc = -EPROTO; | ||
802 | ocfs2_live_connection_drop(control); | ||
803 | goto out; | ||
804 | } | ||
805 | |||
806 | rc = dlm_new_lockspace(conn->cc_name, strlen(conn->cc_name), | ||
807 | &fsdlm, DLM_LSFL_FS, DLM_LVB_LEN); | ||
808 | if (rc) { | ||
809 | ocfs2_live_connection_drop(control); | ||
810 | goto out; | ||
811 | } | ||
812 | |||
813 | conn->cc_private = control; | ||
814 | conn->cc_lockspace = fsdlm; | ||
815 | out: | ||
816 | return rc; | ||
817 | } | ||
818 | |||
819 | static int user_cluster_disconnect(struct ocfs2_cluster_connection *conn, | ||
820 | int hangup_pending) | ||
821 | { | ||
822 | dlm_release_lockspace(conn->cc_lockspace, 2); | ||
823 | conn->cc_lockspace = NULL; | ||
824 | ocfs2_live_connection_drop(conn->cc_private); | ||
825 | conn->cc_private = NULL; | ||
826 | return 0; | ||
827 | } | ||
828 | |||
829 | static int user_cluster_this_node(unsigned int *this_node) | ||
830 | { | ||
831 | int rc; | ||
832 | |||
833 | rc = ocfs2_control_get_this_node(); | ||
834 | if (rc < 0) | ||
835 | return rc; | ||
836 | |||
837 | *this_node = rc; | ||
838 | return 0; | ||
839 | } | ||
840 | |||
841 | static struct ocfs2_stack_operations user_stack_ops = { | ||
842 | .connect = user_cluster_connect, | ||
843 | .disconnect = user_cluster_disconnect, | ||
844 | .this_node = user_cluster_this_node, | ||
845 | .dlm_lock = user_dlm_lock, | ||
846 | .dlm_unlock = user_dlm_unlock, | ||
847 | .lock_status = user_dlm_lock_status, | ||
848 | .lock_lvb = user_dlm_lvb, | ||
849 | .dump_lksb = user_dlm_dump_lksb, | ||
850 | }; | ||
851 | |||
852 | static struct ocfs2_stack_plugin user_stack = { | ||
853 | .sp_name = "user", | ||
854 | .sp_ops = &user_stack_ops, | ||
855 | .sp_owner = THIS_MODULE, | ||
856 | }; | ||
857 | |||
858 | |||
655 | static int __init user_stack_init(void) | 859 | static int __init user_stack_init(void) |
656 | { | 860 | { |
657 | return ocfs2_control_init(); | 861 | int rc; |
862 | |||
863 | rc = ocfs2_control_init(); | ||
864 | if (!rc) { | ||
865 | rc = ocfs2_stack_glue_register(&user_stack); | ||
866 | if (rc) | ||
867 | ocfs2_control_exit(); | ||
868 | } | ||
869 | |||
870 | return rc; | ||
658 | } | 871 | } |
659 | 872 | ||
660 | static void __exit user_stack_exit(void) | 873 | static void __exit user_stack_exit(void) |
661 | { | 874 | { |
875 | ocfs2_stack_glue_unregister(&user_stack); | ||
662 | ocfs2_control_exit(); | 876 | ocfs2_control_exit(); |
663 | } | 877 | } |
664 | 878 | ||
diff --git a/fs/ocfs2/stackglue.c b/fs/ocfs2/stackglue.c index bf45d9bff8a7..119f60cea9cc 100644 --- a/fs/ocfs2/stackglue.c +++ b/fs/ocfs2/stackglue.c | |||
@@ -228,13 +228,20 @@ void ocfs2_stack_glue_set_locking_protocol(struct ocfs2_locking_protocol *proto) | |||
228 | EXPORT_SYMBOL_GPL(ocfs2_stack_glue_set_locking_protocol); | 228 | EXPORT_SYMBOL_GPL(ocfs2_stack_glue_set_locking_protocol); |
229 | 229 | ||
230 | 230 | ||
231 | /* | ||
232 | * The ocfs2_dlm_lock() and ocfs2_dlm_unlock() functions take | ||
233 | * "struct ocfs2_lock_res *astarg" instead of "void *astarg" because the | ||
234 | * underlying stack plugins need to pilfer the lksb off of the lock_res. | ||
235 | * If some other structure needs to be passed as an astarg, the plugins | ||
236 | * will need to be given a different avenue to the lksb. | ||
237 | */ | ||
231 | int ocfs2_dlm_lock(struct ocfs2_cluster_connection *conn, | 238 | int ocfs2_dlm_lock(struct ocfs2_cluster_connection *conn, |
232 | int mode, | 239 | int mode, |
233 | union ocfs2_dlm_lksb *lksb, | 240 | union ocfs2_dlm_lksb *lksb, |
234 | u32 flags, | 241 | u32 flags, |
235 | void *name, | 242 | void *name, |
236 | unsigned int namelen, | 243 | unsigned int namelen, |
237 | void *astarg) | 244 | struct ocfs2_lock_res *astarg) |
238 | { | 245 | { |
239 | BUG_ON(lproto == NULL); | 246 | BUG_ON(lproto == NULL); |
240 | 247 | ||
@@ -246,7 +253,7 @@ EXPORT_SYMBOL_GPL(ocfs2_dlm_lock); | |||
246 | int ocfs2_dlm_unlock(struct ocfs2_cluster_connection *conn, | 253 | int ocfs2_dlm_unlock(struct ocfs2_cluster_connection *conn, |
247 | union ocfs2_dlm_lksb *lksb, | 254 | union ocfs2_dlm_lksb *lksb, |
248 | u32 flags, | 255 | u32 flags, |
249 | void *astarg) | 256 | struct ocfs2_lock_res *astarg) |
250 | { | 257 | { |
251 | BUG_ON(lproto == NULL); | 258 | BUG_ON(lproto == NULL); |
252 | 259 | ||
@@ -360,7 +367,8 @@ void ocfs2_cluster_hangup(const char *group, int grouplen) | |||
360 | BUG_ON(group == NULL); | 367 | BUG_ON(group == NULL); |
361 | BUG_ON(group[grouplen] != '\0'); | 368 | BUG_ON(group[grouplen] != '\0'); |
362 | 369 | ||
363 | active_stack->sp_ops->hangup(group, grouplen); | 370 | if (active_stack->sp_ops->hangup) |
371 | active_stack->sp_ops->hangup(group, grouplen); | ||
364 | 372 | ||
365 | /* cluster_disconnect() was called with hangup_pending==1 */ | 373 | /* cluster_disconnect() was called with hangup_pending==1 */ |
366 | ocfs2_stack_driver_put(); | 374 | ocfs2_stack_driver_put(); |
diff --git a/fs/ocfs2/stackglue.h b/fs/ocfs2/stackglue.h index d88bc655644b..005e4f170e0f 100644 --- a/fs/ocfs2/stackglue.h +++ b/fs/ocfs2/stackglue.h | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/dlmconstants.h> | 26 | #include <linux/dlmconstants.h> |
27 | 27 | ||
28 | #include "dlm/dlmapi.h" | 28 | #include "dlm/dlmapi.h" |
29 | #include <linux/dlm.h> | ||
29 | 30 | ||
30 | /* | 31 | /* |
31 | * dlmconstants.h does not have a LOCAL flag. We hope to remove it | 32 | * dlmconstants.h does not have a LOCAL flag. We hope to remove it |
@@ -60,6 +61,17 @@ struct ocfs2_locking_protocol { | |||
60 | void (*lp_unlock_ast)(void *astarg, int error); | 61 | void (*lp_unlock_ast)(void *astarg, int error); |
61 | }; | 62 | }; |
62 | 63 | ||
64 | |||
65 | /* | ||
66 | * The dlm_lockstatus struct includes lvb space, but the dlm_lksb struct only | ||
67 | * has a pointer to separately allocated lvb space. This struct exists only to | ||
68 | * include in the lksb union to make space for a combined dlm_lksb and lvb. | ||
69 | */ | ||
70 | struct fsdlm_lksb_plus_lvb { | ||
71 | struct dlm_lksb lksb; | ||
72 | char lvb[DLM_LVB_LEN]; | ||
73 | }; | ||
74 | |||
63 | /* | 75 | /* |
64 | * A union of all lock status structures. We define it here so that the | 76 | * A union of all lock status structures. We define it here so that the |
65 | * size of the union is known. Lock status structures are embedded in | 77 | * size of the union is known. Lock status structures are embedded in |
@@ -67,6 +79,8 @@ struct ocfs2_locking_protocol { | |||
67 | */ | 79 | */ |
68 | union ocfs2_dlm_lksb { | 80 | union ocfs2_dlm_lksb { |
69 | struct dlm_lockstatus lksb_o2dlm; | 81 | struct dlm_lockstatus lksb_o2dlm; |
82 | struct dlm_lksb lksb_fsdlm; | ||
83 | struct fsdlm_lksb_plus_lvb padding; | ||
70 | }; | 84 | }; |
71 | 85 | ||
72 | /* | 86 | /* |
@@ -221,17 +235,18 @@ int ocfs2_cluster_disconnect(struct ocfs2_cluster_connection *conn, | |||
221 | void ocfs2_cluster_hangup(const char *group, int grouplen); | 235 | void ocfs2_cluster_hangup(const char *group, int grouplen); |
222 | int ocfs2_cluster_this_node(unsigned int *node); | 236 | int ocfs2_cluster_this_node(unsigned int *node); |
223 | 237 | ||
238 | struct ocfs2_lock_res; | ||
224 | int ocfs2_dlm_lock(struct ocfs2_cluster_connection *conn, | 239 | int ocfs2_dlm_lock(struct ocfs2_cluster_connection *conn, |
225 | int mode, | 240 | int mode, |
226 | union ocfs2_dlm_lksb *lksb, | 241 | union ocfs2_dlm_lksb *lksb, |
227 | u32 flags, | 242 | u32 flags, |
228 | void *name, | 243 | void *name, |
229 | unsigned int namelen, | 244 | unsigned int namelen, |
230 | void *astarg); | 245 | struct ocfs2_lock_res *astarg); |
231 | int ocfs2_dlm_unlock(struct ocfs2_cluster_connection *conn, | 246 | int ocfs2_dlm_unlock(struct ocfs2_cluster_connection *conn, |
232 | union ocfs2_dlm_lksb *lksb, | 247 | union ocfs2_dlm_lksb *lksb, |
233 | u32 flags, | 248 | u32 flags, |
234 | void *astarg); | 249 | struct ocfs2_lock_res *astarg); |
235 | 250 | ||
236 | int ocfs2_dlm_lock_status(union ocfs2_dlm_lksb *lksb); | 251 | int ocfs2_dlm_lock_status(union ocfs2_dlm_lksb *lksb); |
237 | void *ocfs2_dlm_lvb(union ocfs2_dlm_lksb *lksb); | 252 | void *ocfs2_dlm_lvb(union ocfs2_dlm_lksb *lksb); |