Commit 6f2e64d3e1f661095e274c9d9d47e3f39a6cf1c0
1 parent
275a5d24bf
Exists in
master
and in
7 other branches
NFSv4: Make the NFS state model work with the nosharedcache mount option
Consider the case where the user has mounted the remote filesystem server:/foo on the two local directories /bar and /baz using the nosharedcache mount option. The files /bar/file and /baz/file are represented by different inodes in the local namespace, but refer to the same file /foo/file on the server. Consider the case where a process opens both /bar/file and /baz/file, then closes /bar/file: because the nfs4_state is not shared between /bar/file and /baz/file, the kernel will see that the nfs4_state for /bar/file is no longer referenced, so it will send off a CLOSE rpc call. Unless the open_owners differ, then that CLOSE call will invalidate the open state on /baz/file too. Conclusion: we cannot share open state owners between two different non-shared mount instances of the same filesystem. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Showing 2 changed files with 21 additions and 2 deletions Side-by-side Diff
fs/nfs/nfs4_fs.h
fs/nfs/nfs4state.c
... | ... | @@ -156,8 +156,9 @@ |
156 | 156 | } |
157 | 157 | |
158 | 158 | static struct nfs4_state_owner * |
159 | -nfs4_find_state_owner(struct nfs_client *clp, struct rpc_cred *cred) | |
159 | +nfs4_find_state_owner(struct nfs_server *server, struct rpc_cred *cred) | |
160 | 160 | { |
161 | + struct nfs_client *clp = server->nfs_client; | |
161 | 162 | struct rb_node **p = &clp->cl_state_owners.rb_node, |
162 | 163 | *parent = NULL; |
163 | 164 | struct nfs4_state_owner *sp, *res = NULL; |
... | ... | @@ -166,6 +167,14 @@ |
166 | 167 | parent = *p; |
167 | 168 | sp = rb_entry(parent, struct nfs4_state_owner, so_client_node); |
168 | 169 | |
170 | + if (server < sp->so_server) { | |
171 | + p = &parent->rb_left; | |
172 | + continue; | |
173 | + } | |
174 | + if (server > sp->so_server) { | |
175 | + p = &parent->rb_right; | |
176 | + continue; | |
177 | + } | |
169 | 178 | if (cred < sp->so_cred) |
170 | 179 | p = &parent->rb_left; |
171 | 180 | else if (cred > sp->so_cred) |
... | ... | @@ -190,6 +199,14 @@ |
190 | 199 | parent = *p; |
191 | 200 | sp = rb_entry(parent, struct nfs4_state_owner, so_client_node); |
192 | 201 | |
202 | + if (new->so_server < sp->so_server) { | |
203 | + p = &parent->rb_left; | |
204 | + continue; | |
205 | + } | |
206 | + if (new->so_server > sp->so_server) { | |
207 | + p = &parent->rb_right; | |
208 | + continue; | |
209 | + } | |
193 | 210 | if (new->so_cred < sp->so_cred) |
194 | 211 | p = &parent->rb_left; |
195 | 212 | else if (new->so_cred > sp->so_cred) |
... | ... | @@ -260,7 +277,7 @@ |
260 | 277 | struct nfs4_state_owner *sp, *new; |
261 | 278 | |
262 | 279 | spin_lock(&clp->cl_lock); |
263 | - sp = nfs4_find_state_owner(clp, cred); | |
280 | + sp = nfs4_find_state_owner(server, cred); | |
264 | 281 | spin_unlock(&clp->cl_lock); |
265 | 282 | if (sp != NULL) |
266 | 283 | return sp; |
... | ... | @@ -268,6 +285,7 @@ |
268 | 285 | if (new == NULL) |
269 | 286 | return NULL; |
270 | 287 | new->so_client = clp; |
288 | + new->so_server = server; | |
271 | 289 | new->so_cred = cred; |
272 | 290 | spin_lock(&clp->cl_lock); |
273 | 291 | sp = nfs4_insert_state_owner(clp, new); |