diff options
| author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-07-06 10:53:21 -0400 |
|---|---|---|
| committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-07-10 23:40:48 -0400 |
| commit | 6f2e64d3e1f661095e274c9d9d47e3f39a6cf1c0 (patch) | |
| tree | 59bb802bfe2df34ef5666a3d9b7a8f7c21b7247b | |
| parent | 275a5d24bf56b2d9dd4644c54a56366b89a028f1 (diff) | |
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>
| -rw-r--r-- | fs/nfs/nfs4_fs.h | 1 | ||||
| -rw-r--r-- | fs/nfs/nfs4state.c | 22 |
2 files changed, 21 insertions, 2 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index dd1aa2b598ce..6c028e734fe6 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
| @@ -83,6 +83,7 @@ struct nfs_unique_id { | |||
| 83 | struct nfs4_state_owner { | 83 | struct nfs4_state_owner { |
| 84 | struct nfs_unique_id so_owner_id; | 84 | struct nfs_unique_id so_owner_id; |
| 85 | struct nfs_client *so_client; | 85 | struct nfs_client *so_client; |
| 86 | struct nfs_server *so_server; | ||
| 86 | struct rb_node so_client_node; | 87 | struct rb_node so_client_node; |
| 87 | 88 | ||
| 88 | struct rpc_cred *so_cred; /* Associated cred */ | 89 | struct rpc_cred *so_cred; /* Associated cred */ |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 523cc2cbb5e1..e9662ba81d86 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
| @@ -156,8 +156,9 @@ static void nfs_free_unique_id(struct rb_root *root, struct nfs_unique_id *id) | |||
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | static struct nfs4_state_owner * | 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 | struct rb_node **p = &clp->cl_state_owners.rb_node, | 162 | struct rb_node **p = &clp->cl_state_owners.rb_node, |
| 162 | *parent = NULL; | 163 | *parent = NULL; |
| 163 | struct nfs4_state_owner *sp, *res = NULL; | 164 | struct nfs4_state_owner *sp, *res = NULL; |
| @@ -166,6 +167,14 @@ nfs4_find_state_owner(struct nfs_client *clp, struct rpc_cred *cred) | |||
| 166 | parent = *p; | 167 | parent = *p; |
| 167 | sp = rb_entry(parent, struct nfs4_state_owner, so_client_node); | 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 | if (cred < sp->so_cred) | 178 | if (cred < sp->so_cred) |
| 170 | p = &parent->rb_left; | 179 | p = &parent->rb_left; |
| 171 | else if (cred > sp->so_cred) | 180 | else if (cred > sp->so_cred) |
| @@ -190,6 +199,14 @@ nfs4_insert_state_owner(struct nfs_client *clp, struct nfs4_state_owner *new) | |||
| 190 | parent = *p; | 199 | parent = *p; |
| 191 | sp = rb_entry(parent, struct nfs4_state_owner, so_client_node); | 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 | if (new->so_cred < sp->so_cred) | 210 | if (new->so_cred < sp->so_cred) |
| 194 | p = &parent->rb_left; | 211 | p = &parent->rb_left; |
| 195 | else if (new->so_cred > sp->so_cred) | 212 | else if (new->so_cred > sp->so_cred) |
| @@ -260,7 +277,7 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct | |||
| 260 | struct nfs4_state_owner *sp, *new; | 277 | struct nfs4_state_owner *sp, *new; |
| 261 | 278 | ||
| 262 | spin_lock(&clp->cl_lock); | 279 | spin_lock(&clp->cl_lock); |
| 263 | sp = nfs4_find_state_owner(clp, cred); | 280 | sp = nfs4_find_state_owner(server, cred); |
| 264 | spin_unlock(&clp->cl_lock); | 281 | spin_unlock(&clp->cl_lock); |
| 265 | if (sp != NULL) | 282 | if (sp != NULL) |
| 266 | return sp; | 283 | return sp; |
| @@ -268,6 +285,7 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct | |||
| 268 | if (new == NULL) | 285 | if (new == NULL) |
| 269 | return NULL; | 286 | return NULL; |
| 270 | new->so_client = clp; | 287 | new->so_client = clp; |
| 288 | new->so_server = server; | ||
| 271 | new->so_cred = cred; | 289 | new->so_cred = cred; |
| 272 | spin_lock(&clp->cl_lock); | 290 | spin_lock(&clp->cl_lock); |
| 273 | sp = nfs4_insert_state_owner(clp, new); | 291 | sp = nfs4_insert_state_owner(clp, new); |
