diff options
Diffstat (limited to 'fs/lockd/clntlock.c')
-rw-r--r-- | fs/lockd/clntlock.c | 99 |
1 files changed, 58 insertions, 41 deletions
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index 44adb84183b6..006bb9e14579 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c | |||
@@ -42,23 +42,51 @@ struct nlm_wait { | |||
42 | static LIST_HEAD(nlm_blocked); | 42 | static LIST_HEAD(nlm_blocked); |
43 | 43 | ||
44 | /* | 44 | /* |
45 | * Block on a lock | 45 | * Queue up a lock for blocking so that the GRANTED request can see it |
46 | */ | 46 | */ |
47 | int | 47 | int nlmclnt_prepare_block(struct nlm_rqst *req, struct nlm_host *host, struct file_lock *fl) |
48 | nlmclnt_block(struct nlm_host *host, struct file_lock *fl, u32 *statp) | 48 | { |
49 | struct nlm_wait *block; | ||
50 | |||
51 | BUG_ON(req->a_block != NULL); | ||
52 | block = kmalloc(sizeof(*block), GFP_KERNEL); | ||
53 | if (block == NULL) | ||
54 | return -ENOMEM; | ||
55 | block->b_host = host; | ||
56 | block->b_lock = fl; | ||
57 | init_waitqueue_head(&block->b_wait); | ||
58 | block->b_status = NLM_LCK_BLOCKED; | ||
59 | |||
60 | list_add(&block->b_list, &nlm_blocked); | ||
61 | req->a_block = block; | ||
62 | |||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | void nlmclnt_finish_block(struct nlm_rqst *req) | ||
49 | { | 67 | { |
50 | struct nlm_wait block, **head; | 68 | struct nlm_wait *block = req->a_block; |
51 | int err; | ||
52 | u32 pstate; | ||
53 | 69 | ||
54 | block.b_host = host; | 70 | if (block == NULL) |
55 | block.b_lock = fl; | 71 | return; |
56 | init_waitqueue_head(&block.b_wait); | 72 | req->a_block = NULL; |
57 | block.b_status = NLM_LCK_BLOCKED; | 73 | list_del(&block->b_list); |
58 | list_add(&block.b_list, &nlm_blocked); | 74 | kfree(block); |
75 | } | ||
59 | 76 | ||
60 | /* Remember pseudo nsm state */ | 77 | /* |
61 | pstate = host->h_state; | 78 | * Block on a lock |
79 | */ | ||
80 | long nlmclnt_block(struct nlm_rqst *req, long timeout) | ||
81 | { | ||
82 | struct nlm_wait *block = req->a_block; | ||
83 | long ret; | ||
84 | |||
85 | /* A borken server might ask us to block even if we didn't | ||
86 | * request it. Just say no! | ||
87 | */ | ||
88 | if (!req->a_args.block) | ||
89 | return -EAGAIN; | ||
62 | 90 | ||
63 | /* Go to sleep waiting for GRANT callback. Some servers seem | 91 | /* Go to sleep waiting for GRANT callback. Some servers seem |
64 | * to lose callbacks, however, so we're going to poll from | 92 | * to lose callbacks, however, so we're going to poll from |
@@ -68,23 +96,16 @@ nlmclnt_block(struct nlm_host *host, struct file_lock *fl, u32 *statp) | |||
68 | * a 1 minute timeout would do. See the comment before | 96 | * a 1 minute timeout would do. See the comment before |
69 | * nlmclnt_lock for an explanation. | 97 | * nlmclnt_lock for an explanation. |
70 | */ | 98 | */ |
71 | sleep_on_timeout(&block.b_wait, 30*HZ); | 99 | ret = wait_event_interruptible_timeout(block->b_wait, |
100 | block->b_status != NLM_LCK_BLOCKED, | ||
101 | timeout); | ||
72 | 102 | ||
73 | list_del(&block.b_list); | 103 | if (block->b_status != NLM_LCK_BLOCKED) { |
74 | 104 | req->a_res.status = block->b_status; | |
75 | if (!signalled()) { | 105 | block->b_status = NLM_LCK_BLOCKED; |
76 | *statp = block.b_status; | ||
77 | return 0; | ||
78 | } | 106 | } |
79 | 107 | ||
80 | /* Okay, we were interrupted. Cancel the pending request | 108 | return ret; |
81 | * unless the server has rebooted. | ||
82 | */ | ||
83 | if (pstate == host->h_state && (err = nlmclnt_cancel(host, fl)) < 0) | ||
84 | printk(KERN_NOTICE | ||
85 | "lockd: CANCEL call failed (errno %d)\n", -err); | ||
86 | |||
87 | return -ERESTARTSYS; | ||
88 | } | 109 | } |
89 | 110 | ||
90 | /* | 111 | /* |
@@ -94,27 +115,23 @@ u32 | |||
94 | nlmclnt_grant(struct nlm_lock *lock) | 115 | nlmclnt_grant(struct nlm_lock *lock) |
95 | { | 116 | { |
96 | struct nlm_wait *block; | 117 | struct nlm_wait *block; |
118 | u32 res = nlm_lck_denied; | ||
97 | 119 | ||
98 | /* | 120 | /* |
99 | * Look up blocked request based on arguments. | 121 | * Look up blocked request based on arguments. |
100 | * Warning: must not use cookie to match it! | 122 | * Warning: must not use cookie to match it! |
101 | */ | 123 | */ |
102 | list_for_each_entry(block, &nlm_blocked, b_list) { | 124 | list_for_each_entry(block, &nlm_blocked, b_list) { |
103 | if (nlm_compare_locks(block->b_lock, &lock->fl)) | 125 | if (nlm_compare_locks(block->b_lock, &lock->fl)) { |
104 | break; | 126 | /* Alright, we found a lock. Set the return status |
127 | * and wake up the caller | ||
128 | */ | ||
129 | block->b_status = NLM_LCK_GRANTED; | ||
130 | wake_up(&block->b_wait); | ||
131 | res = nlm_granted; | ||
132 | } | ||
105 | } | 133 | } |
106 | 134 | return res; | |
107 | /* Ooops, no blocked request found. */ | ||
108 | if (block == NULL) | ||
109 | return nlm_lck_denied; | ||
110 | |||
111 | /* Alright, we found the lock. Set the return status and | ||
112 | * wake up the caller. | ||
113 | */ | ||
114 | block->b_status = NLM_LCK_GRANTED; | ||
115 | wake_up(&block->b_wait); | ||
116 | |||
117 | return nlm_granted; | ||
118 | } | 135 | } |
119 | 136 | ||
120 | /* | 137 | /* |