diff options
-rw-r--r-- | fs/dlm/user.c | 88 |
1 files changed, 74 insertions, 14 deletions
diff --git a/fs/dlm/user.c b/fs/dlm/user.c index 8b6e73c47435..b6272853130c 100644 --- a/fs/dlm/user.c +++ b/fs/dlm/user.c | |||
@@ -215,6 +215,7 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, int type, int mode) | |||
215 | if (!ast_type) { | 215 | if (!ast_type) { |
216 | kref_get(&lkb->lkb_ref); | 216 | kref_get(&lkb->lkb_ref); |
217 | list_add_tail(&lkb->lkb_astqueue, &proc->asts); | 217 | list_add_tail(&lkb->lkb_astqueue, &proc->asts); |
218 | lkb->lkb_ast_first = type; | ||
218 | wake_up_interruptible(&proc->wait); | 219 | wake_up_interruptible(&proc->wait); |
219 | } | 220 | } |
220 | if (type == AST_COMP && (ast_type & AST_COMP)) | 221 | if (type == AST_COMP && (ast_type & AST_COMP)) |
@@ -223,7 +224,6 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, int type, int mode) | |||
223 | 224 | ||
224 | eol = lkb_is_endoflife(lkb, ua->lksb.sb_status, type); | 225 | eol = lkb_is_endoflife(lkb, ua->lksb.sb_status, type); |
225 | if (eol) { | 226 | if (eol) { |
226 | lkb->lkb_ast_type &= ~AST_BAST; | ||
227 | lkb->lkb_flags |= DLM_IFL_ENDOFLIFE; | 227 | lkb->lkb_flags |= DLM_IFL_ENDOFLIFE; |
228 | } | 228 | } |
229 | 229 | ||
@@ -706,7 +706,7 @@ static int device_close(struct inode *inode, struct file *file) | |||
706 | } | 706 | } |
707 | 707 | ||
708 | static int copy_result_to_user(struct dlm_user_args *ua, int compat, int type, | 708 | static int copy_result_to_user(struct dlm_user_args *ua, int compat, int type, |
709 | int bmode, char __user *buf, size_t count) | 709 | int mode, char __user *buf, size_t count) |
710 | { | 710 | { |
711 | #ifdef CONFIG_COMPAT | 711 | #ifdef CONFIG_COMPAT |
712 | struct dlm_lock_result32 result32; | 712 | struct dlm_lock_result32 result32; |
@@ -733,7 +733,7 @@ static int copy_result_to_user(struct dlm_user_args *ua, int compat, int type, | |||
733 | if (type == AST_BAST) { | 733 | if (type == AST_BAST) { |
734 | result.user_astaddr = ua->bastaddr; | 734 | result.user_astaddr = ua->bastaddr; |
735 | result.user_astparam = ua->bastparam; | 735 | result.user_astparam = ua->bastparam; |
736 | result.bast_mode = bmode; | 736 | result.bast_mode = mode; |
737 | } else { | 737 | } else { |
738 | result.user_astaddr = ua->castaddr; | 738 | result.user_astaddr = ua->castaddr; |
739 | result.user_astparam = ua->castparam; | 739 | result.user_astparam = ua->castparam; |
@@ -801,7 +801,9 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count, | |||
801 | struct dlm_user_proc *proc = file->private_data; | 801 | struct dlm_user_proc *proc = file->private_data; |
802 | struct dlm_lkb *lkb; | 802 | struct dlm_lkb *lkb; |
803 | DECLARE_WAITQUEUE(wait, current); | 803 | DECLARE_WAITQUEUE(wait, current); |
804 | int error, type=0, bmode=0, removed = 0; | 804 | int error = 0, removed; |
805 | int ret_type, ret_mode; | ||
806 | int bastmode, castmode, do_bast, do_cast; | ||
805 | 807 | ||
806 | if (count == sizeof(struct dlm_device_version)) { | 808 | if (count == sizeof(struct dlm_device_version)) { |
807 | error = copy_version_to_user(buf, count); | 809 | error = copy_version_to_user(buf, count); |
@@ -820,6 +822,8 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count, | |||
820 | #endif | 822 | #endif |
821 | return -EINVAL; | 823 | return -EINVAL; |
822 | 824 | ||
825 | try_another: | ||
826 | |||
823 | /* do we really need this? can a read happen after a close? */ | 827 | /* do we really need this? can a read happen after a close? */ |
824 | if (test_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags)) | 828 | if (test_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags)) |
825 | return -EINVAL; | 829 | return -EINVAL; |
@@ -855,13 +859,55 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count, | |||
855 | 859 | ||
856 | lkb = list_entry(proc->asts.next, struct dlm_lkb, lkb_astqueue); | 860 | lkb = list_entry(proc->asts.next, struct dlm_lkb, lkb_astqueue); |
857 | 861 | ||
858 | if (lkb->lkb_ast_type & AST_COMP) { | 862 | removed = 0; |
859 | lkb->lkb_ast_type &= ~AST_COMP; | 863 | ret_type = 0; |
860 | type = AST_COMP; | 864 | ret_mode = 0; |
861 | } else if (lkb->lkb_ast_type & AST_BAST) { | 865 | do_bast = lkb->lkb_ast_type & AST_BAST; |
862 | lkb->lkb_ast_type &= ~AST_BAST; | 866 | do_cast = lkb->lkb_ast_type & AST_COMP; |
863 | type = AST_BAST; | 867 | bastmode = lkb->lkb_bastmode; |
864 | bmode = lkb->lkb_bastmode; | 868 | castmode = lkb->lkb_castmode; |
869 | |||
870 | /* when both are queued figure out which to do first and | ||
871 | switch first so the other goes in the next read */ | ||
872 | |||
873 | if (do_cast && do_bast) { | ||
874 | if (lkb->lkb_ast_first == AST_COMP) { | ||
875 | ret_type = AST_COMP; | ||
876 | ret_mode = castmode; | ||
877 | lkb->lkb_ast_type &= ~AST_COMP; | ||
878 | lkb->lkb_ast_first = AST_BAST; | ||
879 | } else { | ||
880 | ret_type = AST_BAST; | ||
881 | ret_mode = bastmode; | ||
882 | lkb->lkb_ast_type &= ~AST_BAST; | ||
883 | lkb->lkb_ast_first = AST_COMP; | ||
884 | } | ||
885 | } else { | ||
886 | ret_type = lkb->lkb_ast_first; | ||
887 | ret_mode = (ret_type == AST_COMP) ? castmode : bastmode; | ||
888 | lkb->lkb_ast_type &= ~ret_type; | ||
889 | lkb->lkb_ast_first = 0; | ||
890 | } | ||
891 | |||
892 | /* if we're doing a bast but the bast is unnecessary, then | ||
893 | switch to do nothing or do a cast if that was needed next */ | ||
894 | |||
895 | if ((ret_type == AST_BAST) && | ||
896 | dlm_modes_compat(bastmode, lkb->lkb_castmode_done)) { | ||
897 | ret_type = 0; | ||
898 | ret_mode = 0; | ||
899 | |||
900 | if (do_cast) { | ||
901 | ret_type = AST_COMP; | ||
902 | ret_mode = castmode; | ||
903 | lkb->lkb_ast_type &= ~AST_COMP; | ||
904 | lkb->lkb_ast_first = 0; | ||
905 | } | ||
906 | } | ||
907 | |||
908 | if (lkb->lkb_ast_first != lkb->lkb_ast_type) { | ||
909 | log_print("device_read %x ast_first %x ast_type %x", | ||
910 | lkb->lkb_id, lkb->lkb_ast_first, lkb->lkb_ast_type); | ||
865 | } | 911 | } |
866 | 912 | ||
867 | if (!lkb->lkb_ast_type) { | 913 | if (!lkb->lkb_ast_type) { |
@@ -870,15 +916,29 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count, | |||
870 | } | 916 | } |
871 | spin_unlock(&proc->asts_spin); | 917 | spin_unlock(&proc->asts_spin); |
872 | 918 | ||
873 | error = copy_result_to_user(lkb->lkb_ua, | 919 | if (ret_type) { |
874 | test_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags), | 920 | error = copy_result_to_user(lkb->lkb_ua, |
875 | type, bmode, buf, count); | 921 | test_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags), |
922 | ret_type, ret_mode, buf, count); | ||
923 | |||
924 | if (ret_type == AST_COMP) | ||
925 | lkb->lkb_castmode_done = castmode; | ||
926 | if (ret_type == AST_BAST) | ||
927 | lkb->lkb_bastmode_done = bastmode; | ||
928 | } | ||
876 | 929 | ||
877 | /* removes reference for the proc->asts lists added by | 930 | /* removes reference for the proc->asts lists added by |
878 | dlm_user_add_ast() and may result in the lkb being freed */ | 931 | dlm_user_add_ast() and may result in the lkb being freed */ |
932 | |||
879 | if (removed) | 933 | if (removed) |
880 | dlm_put_lkb(lkb); | 934 | dlm_put_lkb(lkb); |
881 | 935 | ||
936 | /* the bast that was queued was eliminated (see unnecessary above), | ||
937 | leaving nothing to return */ | ||
938 | |||
939 | if (!ret_type) | ||
940 | goto try_another; | ||
941 | |||
882 | return error; | 942 | return error; |
883 | } | 943 | } |
884 | 944 | ||