diff options
Diffstat (limited to 'fs/lockd/clntlock.c')
-rw-r--r-- | fs/lockd/clntlock.c | 113 |
1 files changed, 62 insertions, 51 deletions
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index ef7103b8c5bd..006bb9e14579 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c | |||
@@ -31,7 +31,7 @@ static int reclaimer(void *ptr); | |||
31 | * This is the representation of a blocked client lock. | 31 | * This is the representation of a blocked client lock. |
32 | */ | 32 | */ |
33 | struct nlm_wait { | 33 | struct nlm_wait { |
34 | struct nlm_wait * b_next; /* linked list */ | 34 | struct list_head b_list; /* linked list */ |
35 | wait_queue_head_t b_wait; /* where to wait on */ | 35 | wait_queue_head_t b_wait; /* where to wait on */ |
36 | struct nlm_host * b_host; | 36 | struct nlm_host * b_host; |
37 | struct file_lock * b_lock; /* local file lock */ | 37 | struct file_lock * b_lock; /* local file lock */ |
@@ -39,27 +39,54 @@ struct nlm_wait { | |||
39 | u32 b_status; /* grant callback status */ | 39 | u32 b_status; /* grant callback status */ |
40 | }; | 40 | }; |
41 | 41 | ||
42 | static struct nlm_wait * 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 | block.b_next = nlm_blocked; | 74 | kfree(block); |
59 | nlm_blocked = █ | 75 | } |
76 | |||
77 | /* | ||
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; | ||
60 | 84 | ||
61 | /* Remember pseudo nsm state */ | 85 | /* A borken server might ask us to block even if we didn't |
62 | pstate = host->h_state; | 86 | * request it. Just say no! |
87 | */ | ||
88 | if (!req->a_args.block) | ||
89 | return -EAGAIN; | ||
63 | 90 | ||
64 | /* Go to sleep waiting for GRANT callback. Some servers seem | 91 | /* Go to sleep waiting for GRANT callback. Some servers seem |
65 | * to lose callbacks, however, so we're going to poll from | 92 | * to lose callbacks, however, so we're going to poll from |
@@ -69,28 +96,16 @@ nlmclnt_block(struct nlm_host *host, struct file_lock *fl, u32 *statp) | |||
69 | * a 1 minute timeout would do. See the comment before | 96 | * a 1 minute timeout would do. See the comment before |
70 | * nlmclnt_lock for an explanation. | 97 | * nlmclnt_lock for an explanation. |
71 | */ | 98 | */ |
72 | sleep_on_timeout(&block.b_wait, 30*HZ); | 99 | ret = wait_event_interruptible_timeout(block->b_wait, |
73 | 100 | block->b_status != NLM_LCK_BLOCKED, | |
74 | for (head = &nlm_blocked; *head; head = &(*head)->b_next) { | 101 | timeout); |
75 | if (*head == &block) { | ||
76 | *head = block.b_next; | ||
77 | break; | ||
78 | } | ||
79 | } | ||
80 | 102 | ||
81 | if (!signalled()) { | 103 | if (block->b_status != NLM_LCK_BLOCKED) { |
82 | *statp = block.b_status; | 104 | req->a_res.status = block->b_status; |
83 | return 0; | 105 | block->b_status = NLM_LCK_BLOCKED; |
84 | } | 106 | } |
85 | 107 | ||
86 | /* Okay, we were interrupted. Cancel the pending request | 108 | return ret; |
87 | * unless the server has rebooted. | ||
88 | */ | ||
89 | if (pstate == host->h_state && (err = nlmclnt_cancel(host, fl)) < 0) | ||
90 | printk(KERN_NOTICE | ||
91 | "lockd: CANCEL call failed (errno %d)\n", -err); | ||
92 | |||
93 | return -ERESTARTSYS; | ||
94 | } | 109 | } |
95 | 110 | ||
96 | /* | 111 | /* |
@@ -100,27 +115,23 @@ u32 | |||
100 | nlmclnt_grant(struct nlm_lock *lock) | 115 | nlmclnt_grant(struct nlm_lock *lock) |
101 | { | 116 | { |
102 | struct nlm_wait *block; | 117 | struct nlm_wait *block; |
118 | u32 res = nlm_lck_denied; | ||
103 | 119 | ||
104 | /* | 120 | /* |
105 | * Look up blocked request based on arguments. | 121 | * Look up blocked request based on arguments. |
106 | * Warning: must not use cookie to match it! | 122 | * Warning: must not use cookie to match it! |
107 | */ | 123 | */ |
108 | for (block = nlm_blocked; block; block = block->b_next) { | 124 | list_for_each_entry(block, &nlm_blocked, b_list) { |
109 | if (nlm_compare_locks(block->b_lock, &lock->fl)) | 125 | if (nlm_compare_locks(block->b_lock, &lock->fl)) { |
110 | 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 | } | ||
111 | } | 133 | } |
112 | 134 | return res; | |
113 | /* Ooops, no blocked request found. */ | ||
114 | if (block == NULL) | ||
115 | return nlm_lck_denied; | ||
116 | |||
117 | /* Alright, we found the lock. Set the return status and | ||
118 | * wake up the caller. | ||
119 | */ | ||
120 | block->b_status = NLM_LCK_GRANTED; | ||
121 | wake_up(&block->b_wait); | ||
122 | |||
123 | return nlm_granted; | ||
124 | } | 135 | } |
125 | 136 | ||
126 | /* | 137 | /* |
@@ -230,7 +241,7 @@ restart: | |||
230 | host->h_reclaiming = 0; | 241 | host->h_reclaiming = 0; |
231 | 242 | ||
232 | /* Now, wake up all processes that sleep on a blocked lock */ | 243 | /* Now, wake up all processes that sleep on a blocked lock */ |
233 | for (block = nlm_blocked; block; block = block->b_next) { | 244 | list_for_each_entry(block, &nlm_blocked, b_list) { |
234 | if (block->b_host == host) { | 245 | if (block->b_host == host) { |
235 | block->b_status = NLM_LCK_DENIED_GRACE_PERIOD; | 246 | block->b_status = NLM_LCK_DENIED_GRACE_PERIOD; |
236 | wake_up(&block->b_wait); | 247 | wake_up(&block->b_wait); |