diff options
author | Olaf Kirch <okir@suse.de> | 2006-10-04 05:16:03 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-04 10:55:18 -0400 |
commit | 39be4502cb75dc26007fe1659735b26c8e63fcc6 (patch) | |
tree | 0f4c6bf14f8a975178b3192bfc9ba942da56619f | |
parent | 031d869d0e0be18cfe35526be5608225b8f0a7be (diff) |
[PATCH] knfsd: match GRANTED_RES replies using cookies
When we send a GRANTED_MSG call, we current copy the NLM cookie provided in
the original LOCK call - because in 1996, some broken clients seemed to rely
on this bug. However, this means the cookies are not unique, so that when the
client's GRANTED_RES message comes back, we cannot simply match it based on
the cookie, but have to use the client's IP address in addition. Which breaks
when you have a multi-homed NFS client.
The X/Open spec explicitly mentions that clients should not expect the same
cookie; so one may hope that any clients that were broken in 1996 have either
been fixed or rendered obsolete.
Signed-off-by: Olaf Kirch <okir@suse.de>
Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | fs/lockd/svc4proc.c | 2 | ||||
-rw-r--r-- | fs/lockd/svclock.c | 24 | ||||
-rw-r--r-- | fs/lockd/svcproc.c | 2 | ||||
-rw-r--r-- | include/linux/lockd/lockd.h | 2 |
4 files changed, 16 insertions, 14 deletions
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index b8525fb62934..fa370f6eb07b 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c | |||
@@ -455,7 +455,7 @@ nlm4svc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp, | |||
455 | 455 | ||
456 | dprintk("lockd: GRANTED_RES called\n"); | 456 | dprintk("lockd: GRANTED_RES called\n"); |
457 | 457 | ||
458 | nlmsvc_grant_reply(rqstp, &argp->cookie, argp->status); | 458 | nlmsvc_grant_reply(&argp->cookie, argp->status); |
459 | return rpc_success; | 459 | return rpc_success; |
460 | } | 460 | } |
461 | 461 | ||
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 1f91567a1b88..3d2b8a831be5 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c | |||
@@ -139,19 +139,19 @@ static inline int nlm_cookie_match(struct nlm_cookie *a, struct nlm_cookie *b) | |||
139 | * Find a block with a given NLM cookie. | 139 | * Find a block with a given NLM cookie. |
140 | */ | 140 | */ |
141 | static inline struct nlm_block * | 141 | static inline struct nlm_block * |
142 | nlmsvc_find_block(struct nlm_cookie *cookie, struct sockaddr_in *sin) | 142 | nlmsvc_find_block(struct nlm_cookie *cookie) |
143 | { | 143 | { |
144 | struct nlm_block *block; | 144 | struct nlm_block *block; |
145 | 145 | ||
146 | list_for_each_entry(block, &nlm_blocked, b_list) { | 146 | list_for_each_entry(block, &nlm_blocked, b_list) { |
147 | if (nlm_cookie_match(&block->b_call->a_args.cookie,cookie) | 147 | if (nlm_cookie_match(&block->b_call->a_args.cookie,cookie)) |
148 | && nlm_cmp_addr(sin, &block->b_host->h_addr)) | ||
149 | goto found; | 148 | goto found; |
150 | } | 149 | } |
151 | 150 | ||
152 | return NULL; | 151 | return NULL; |
153 | 152 | ||
154 | found: | 153 | found: |
154 | dprintk("nlmsvc_find_block(%s): block=%p\n", nlmdbg_cookie2a(cookie), block); | ||
155 | kref_get(&block->b_count); | 155 | kref_get(&block->b_count); |
156 | return block; | 156 | return block; |
157 | } | 157 | } |
@@ -165,6 +165,11 @@ found: | |||
165 | * request, but (as I found out later) that's because some implementations | 165 | * request, but (as I found out later) that's because some implementations |
166 | * do just this. Never mind the standards comittees, they support our | 166 | * do just this. Never mind the standards comittees, they support our |
167 | * logging industries. | 167 | * logging industries. |
168 | * | ||
169 | * 10 years later: I hope we can safely ignore these old and broken | ||
170 | * clients by now. Let's fix this so we can uniquely identify an incoming | ||
171 | * GRANTED_RES message by cookie, without having to rely on the client's IP | ||
172 | * address. --okir | ||
168 | */ | 173 | */ |
169 | static inline struct nlm_block * | 174 | static inline struct nlm_block * |
170 | nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file, | 175 | nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file, |
@@ -197,7 +202,7 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file, | |||
197 | /* Set notifier function for VFS, and init args */ | 202 | /* Set notifier function for VFS, and init args */ |
198 | call->a_args.lock.fl.fl_flags |= FL_SLEEP; | 203 | call->a_args.lock.fl.fl_flags |= FL_SLEEP; |
199 | call->a_args.lock.fl.fl_lmops = &nlmsvc_lock_operations; | 204 | call->a_args.lock.fl.fl_lmops = &nlmsvc_lock_operations; |
200 | call->a_args.cookie = *cookie; /* see above */ | 205 | nlmclnt_next_cookie(&call->a_args.cookie); |
201 | 206 | ||
202 | dprintk("lockd: created block %p...\n", block); | 207 | dprintk("lockd: created block %p...\n", block); |
203 | 208 | ||
@@ -640,17 +645,14 @@ static const struct rpc_call_ops nlmsvc_grant_ops = { | |||
640 | * block. | 645 | * block. |
641 | */ | 646 | */ |
642 | void | 647 | void |
643 | nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status) | 648 | nlmsvc_grant_reply(struct nlm_cookie *cookie, u32 status) |
644 | { | 649 | { |
645 | struct nlm_block *block; | 650 | struct nlm_block *block; |
646 | struct nlm_file *file; | ||
647 | 651 | ||
648 | dprintk("grant_reply: looking for cookie %x, host (%08x), s=%d \n", | 652 | dprintk("grant_reply: looking for cookie %x, s=%d \n", |
649 | *(unsigned int *)(cookie->data), | 653 | *(unsigned int *)(cookie->data), status); |
650 | ntohl(rqstp->rq_addr.sin_addr.s_addr), status); | 654 | if (!(block = nlmsvc_find_block(cookie))) |
651 | if (!(block = nlmsvc_find_block(cookie, &rqstp->rq_addr))) | ||
652 | return; | 655 | return; |
653 | file = block->b_file; | ||
654 | 656 | ||
655 | if (block) { | 657 | if (block) { |
656 | if (status == NLM_LCK_DENIED_GRACE_PERIOD) { | 658 | if (status == NLM_LCK_DENIED_GRACE_PERIOD) { |
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index 66e7b0b3430e..75b2c81bcb93 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c | |||
@@ -484,7 +484,7 @@ nlmsvc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp, | |||
484 | 484 | ||
485 | dprintk("lockd: GRANTED_RES called\n"); | 485 | dprintk("lockd: GRANTED_RES called\n"); |
486 | 486 | ||
487 | nlmsvc_grant_reply(rqstp, &argp->cookie, argp->status); | 487 | nlmsvc_grant_reply(&argp->cookie, argp->status); |
488 | return rpc_success; | 488 | return rpc_success; |
489 | } | 489 | } |
490 | 490 | ||
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index a345650e5622..5920ecaeed66 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h | |||
@@ -193,7 +193,7 @@ u32 nlmsvc_cancel_blocked(struct nlm_file *, struct nlm_lock *); | |||
193 | unsigned long nlmsvc_retry_blocked(void); | 193 | unsigned long nlmsvc_retry_blocked(void); |
194 | void nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *, | 194 | void nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *, |
195 | nlm_host_match_fn_t match); | 195 | nlm_host_match_fn_t match); |
196 | void nlmsvc_grant_reply(struct svc_rqst *, struct nlm_cookie *, u32); | 196 | void nlmsvc_grant_reply(struct nlm_cookie *, u32); |
197 | 197 | ||
198 | /* | 198 | /* |
199 | * File handling for the server personality | 199 | * File handling for the server personality |