diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-07 15:57:46 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-07 15:57:46 -0500 |
commit | c224b76b560f3c65f0d10fbb59d3f00379eb0aaf (patch) | |
tree | 4af73496d5a8322edc1de196a9b904c8264761a1 /fs | |
parent | a1212d278c05ca0a38f5cbd7ae90ac2e367228a8 (diff) | |
parent | fab99ebe39fe7d11fbd9b5fb84f07432af9ba36f (diff) |
Merge tag 'nfs-for-3.13-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client updates from Trond Myklebust:
"Highlights include:
- Changes to the RPC socket code to allow NFSv4 to turn off
timeout+retry:
* Detect TCP connection breakage through the "keepalive" mechanism
- Add client side support for NFSv4.x migration (Chuck Lever)
- Add support for multiple security flavour arguments to the "sec="
mount option (Dros Adamson)
- fs-cache bugfixes from David Howells:
* Fix an issue whereby caching can be enabled on a file that is
open for writing
- More NFSv4 open code stable bugfixes
- Various Labeled NFS (selinux) bugfixes, including one stable fix
- Fix buffer overflow checking in the RPCSEC_GSS upcall encoding"
* tag 'nfs-for-3.13-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (68 commits)
NFSv4.2: Remove redundant checks in nfs_setsecurity+nfs4_label_init_security
NFSv4: Sanity check the server reply in _nfs4_server_capabilities
NFSv4.2: encode_readdir - only ask for labels when doing readdirplus
nfs: set security label when revalidating inode
NFSv4.2: Fix a mismatch between Linux labeled NFS and the NFSv4.2 spec
NFS: Fix a missing initialisation when reading the SELinux label
nfs: fix oops when trying to set SELinux label
nfs: fix inverted test for delegation in nfs4_reclaim_open_state
SUNRPC: Cleanup xs_destroy()
SUNRPC: close a rare race in xs_tcp_setup_socket.
SUNRPC: remove duplicated include from clnt.c
nfs: use IS_ROOT not DCACHE_DISCONNECTED
SUNRPC: Fix buffer overflow checking in gss_encode_v0_msg/gss_encode_v1_msg
SUNRPC: gss_alloc_msg - choose _either_ a v0 message or a v1 message
SUNRPC: remove an unnecessary if statement
nfs: Use PTR_ERR_OR_ZERO in 'nfs/nfs4super.c'
nfs: Use PTR_ERR_OR_ZERO in 'nfs41_callback_up' function
nfs: Remove useless 'error' assignment
sunrpc: comment typo fix
SUNRPC: Add correct rcu_dereference annotation in rpc_clnt_set_transport
...
Diffstat (limited to 'fs')
-rw-r--r-- | fs/9p/cache.c | 6 | ||||
-rw-r--r-- | fs/afs/cell.c | 2 | ||||
-rw-r--r-- | fs/afs/inode.c | 2 | ||||
-rw-r--r-- | fs/afs/vlocation.c | 3 | ||||
-rw-r--r-- | fs/afs/volume.c | 2 | ||||
-rw-r--r-- | fs/cachefiles/interface.c | 2 | ||||
-rw-r--r-- | fs/ceph/cache.c | 4 | ||||
-rw-r--r-- | fs/cifs/fscache.c | 8 | ||||
-rw-r--r-- | fs/fscache/cookie.c | 193 | ||||
-rw-r--r-- | fs/fscache/fsdef.c | 1 | ||||
-rw-r--r-- | fs/fscache/netfs.c | 1 | ||||
-rw-r--r-- | fs/fscache/object.c | 7 | ||||
-rw-r--r-- | fs/fscache/page.c | 59 | ||||
-rw-r--r-- | fs/nfs/Kconfig | 11 | ||||
-rw-r--r-- | fs/nfs/callback.c | 3 | ||||
-rw-r--r-- | fs/nfs/client.c | 10 | ||||
-rw-r--r-- | fs/nfs/dir.c | 10 | ||||
-rw-r--r-- | fs/nfs/fscache.c | 202 | ||||
-rw-r--r-- | fs/nfs/fscache.h | 18 | ||||
-rw-r--r-- | fs/nfs/inode.c | 16 | ||||
-rw-r--r-- | fs/nfs/internal.h | 8 | ||||
-rw-r--r-- | fs/nfs/nfs4_fs.h | 17 | ||||
-rw-r--r-- | fs/nfs/nfs4client.c | 138 | ||||
-rw-r--r-- | fs/nfs/nfs4file.c | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4namespace.c | 118 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 470 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 264 | ||||
-rw-r--r-- | fs/nfs/nfs4super.c | 12 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 138 | ||||
-rw-r--r-- | fs/nfs/super.c | 198 | ||||
-rw-r--r-- | fs/nfs/unlink.c | 3 |
31 files changed, 1475 insertions, 453 deletions
diff --git a/fs/9p/cache.c b/fs/9p/cache.c index a9ea73d6dcf3..2b7a032c37bc 100644 --- a/fs/9p/cache.c +++ b/fs/9p/cache.c | |||
@@ -90,7 +90,7 @@ void v9fs_cache_session_get_cookie(struct v9fs_session_info *v9ses) | |||
90 | 90 | ||
91 | v9ses->fscache = fscache_acquire_cookie(v9fs_cache_netfs.primary_index, | 91 | v9ses->fscache = fscache_acquire_cookie(v9fs_cache_netfs.primary_index, |
92 | &v9fs_cache_session_index_def, | 92 | &v9fs_cache_session_index_def, |
93 | v9ses); | 93 | v9ses, true); |
94 | p9_debug(P9_DEBUG_FSC, "session %p get cookie %p\n", | 94 | p9_debug(P9_DEBUG_FSC, "session %p get cookie %p\n", |
95 | v9ses, v9ses->fscache); | 95 | v9ses, v9ses->fscache); |
96 | } | 96 | } |
@@ -204,7 +204,7 @@ void v9fs_cache_inode_get_cookie(struct inode *inode) | |||
204 | v9ses = v9fs_inode2v9ses(inode); | 204 | v9ses = v9fs_inode2v9ses(inode); |
205 | v9inode->fscache = fscache_acquire_cookie(v9ses->fscache, | 205 | v9inode->fscache = fscache_acquire_cookie(v9ses->fscache, |
206 | &v9fs_cache_inode_index_def, | 206 | &v9fs_cache_inode_index_def, |
207 | v9inode); | 207 | v9inode, true); |
208 | 208 | ||
209 | p9_debug(P9_DEBUG_FSC, "inode %p get cookie %p\n", | 209 | p9_debug(P9_DEBUG_FSC, "inode %p get cookie %p\n", |
210 | inode, v9inode->fscache); | 210 | inode, v9inode->fscache); |
@@ -271,7 +271,7 @@ void v9fs_cache_inode_reset_cookie(struct inode *inode) | |||
271 | v9ses = v9fs_inode2v9ses(inode); | 271 | v9ses = v9fs_inode2v9ses(inode); |
272 | v9inode->fscache = fscache_acquire_cookie(v9ses->fscache, | 272 | v9inode->fscache = fscache_acquire_cookie(v9ses->fscache, |
273 | &v9fs_cache_inode_index_def, | 273 | &v9fs_cache_inode_index_def, |
274 | v9inode); | 274 | v9inode, true); |
275 | p9_debug(P9_DEBUG_FSC, "inode %p revalidating cookie old %p new %p\n", | 275 | p9_debug(P9_DEBUG_FSC, "inode %p revalidating cookie old %p new %p\n", |
276 | inode, old, v9inode->fscache); | 276 | inode, old, v9inode->fscache); |
277 | 277 | ||
diff --git a/fs/afs/cell.c b/fs/afs/cell.c index 3c090b7555ea..ca0a3cf93791 100644 --- a/fs/afs/cell.c +++ b/fs/afs/cell.c | |||
@@ -179,7 +179,7 @@ struct afs_cell *afs_cell_create(const char *name, unsigned namesz, | |||
179 | /* put it up for caching (this never returns an error) */ | 179 | /* put it up for caching (this never returns an error) */ |
180 | cell->cache = fscache_acquire_cookie(afs_cache_netfs.primary_index, | 180 | cell->cache = fscache_acquire_cookie(afs_cache_netfs.primary_index, |
181 | &afs_cell_cache_index_def, | 181 | &afs_cell_cache_index_def, |
182 | cell); | 182 | cell, true); |
183 | #endif | 183 | #endif |
184 | 184 | ||
185 | /* add to the cell lists */ | 185 | /* add to the cell lists */ |
diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 789bc253b5f6..ce25d755b7aa 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c | |||
@@ -259,7 +259,7 @@ struct inode *afs_iget(struct super_block *sb, struct key *key, | |||
259 | #ifdef CONFIG_AFS_FSCACHE | 259 | #ifdef CONFIG_AFS_FSCACHE |
260 | vnode->cache = fscache_acquire_cookie(vnode->volume->cache, | 260 | vnode->cache = fscache_acquire_cookie(vnode->volume->cache, |
261 | &afs_vnode_cache_index_def, | 261 | &afs_vnode_cache_index_def, |
262 | vnode); | 262 | vnode, true); |
263 | #endif | 263 | #endif |
264 | 264 | ||
265 | ret = afs_inode_map_status(vnode, key); | 265 | ret = afs_inode_map_status(vnode, key); |
diff --git a/fs/afs/vlocation.c b/fs/afs/vlocation.c index 57bcb1596530..b6df2e83809f 100644 --- a/fs/afs/vlocation.c +++ b/fs/afs/vlocation.c | |||
@@ -308,7 +308,8 @@ static int afs_vlocation_fill_in_record(struct afs_vlocation *vl, | |||
308 | /* see if we have an in-cache copy (will set vl->valid if there is) */ | 308 | /* see if we have an in-cache copy (will set vl->valid if there is) */ |
309 | #ifdef CONFIG_AFS_FSCACHE | 309 | #ifdef CONFIG_AFS_FSCACHE |
310 | vl->cache = fscache_acquire_cookie(vl->cell->cache, | 310 | vl->cache = fscache_acquire_cookie(vl->cell->cache, |
311 | &afs_vlocation_cache_index_def, vl); | 311 | &afs_vlocation_cache_index_def, vl, |
312 | true); | ||
312 | #endif | 313 | #endif |
313 | 314 | ||
314 | if (vl->valid) { | 315 | if (vl->valid) { |
diff --git a/fs/afs/volume.c b/fs/afs/volume.c index 401eeb21869f..2b607257820c 100644 --- a/fs/afs/volume.c +++ b/fs/afs/volume.c | |||
@@ -131,7 +131,7 @@ struct afs_volume *afs_volume_lookup(struct afs_mount_params *params) | |||
131 | #ifdef CONFIG_AFS_FSCACHE | 131 | #ifdef CONFIG_AFS_FSCACHE |
132 | volume->cache = fscache_acquire_cookie(vlocation->cache, | 132 | volume->cache = fscache_acquire_cookie(vlocation->cache, |
133 | &afs_volume_cache_index_def, | 133 | &afs_volume_cache_index_def, |
134 | volume); | 134 | volume, true); |
135 | #endif | 135 | #endif |
136 | afs_get_vlocation(vlocation); | 136 | afs_get_vlocation(vlocation); |
137 | volume->vlocation = vlocation; | 137 | volume->vlocation = vlocation; |
diff --git a/fs/cachefiles/interface.c b/fs/cachefiles/interface.c index 43eb5592cdea..00baf1419989 100644 --- a/fs/cachefiles/interface.c +++ b/fs/cachefiles/interface.c | |||
@@ -270,7 +270,7 @@ static void cachefiles_drop_object(struct fscache_object *_object) | |||
270 | #endif | 270 | #endif |
271 | 271 | ||
272 | /* delete retired objects */ | 272 | /* delete retired objects */ |
273 | if (test_bit(FSCACHE_COOKIE_RETIRED, &object->fscache.cookie->flags) && | 273 | if (test_bit(FSCACHE_OBJECT_RETIRED, &object->fscache.flags) && |
274 | _object != cache->cache.fsdef | 274 | _object != cache->cache.fsdef |
275 | ) { | 275 | ) { |
276 | _debug("- retire object OBJ%x", object->fscache.debug_id); | 276 | _debug("- retire object OBJ%x", object->fscache.debug_id); |
diff --git a/fs/ceph/cache.c b/fs/ceph/cache.c index 6bfe65e0b038..7db2e6ca4b8f 100644 --- a/fs/ceph/cache.c +++ b/fs/ceph/cache.c | |||
@@ -68,7 +68,7 @@ int ceph_fscache_register_fs(struct ceph_fs_client* fsc) | |||
68 | { | 68 | { |
69 | fsc->fscache = fscache_acquire_cookie(ceph_cache_netfs.primary_index, | 69 | fsc->fscache = fscache_acquire_cookie(ceph_cache_netfs.primary_index, |
70 | &ceph_fscache_fsid_object_def, | 70 | &ceph_fscache_fsid_object_def, |
71 | fsc); | 71 | fsc, true); |
72 | 72 | ||
73 | if (fsc->fscache == NULL) { | 73 | if (fsc->fscache == NULL) { |
74 | pr_err("Unable to resgister fsid: %p fscache cookie", fsc); | 74 | pr_err("Unable to resgister fsid: %p fscache cookie", fsc); |
@@ -204,7 +204,7 @@ void ceph_fscache_register_inode_cookie(struct ceph_fs_client* fsc, | |||
204 | 204 | ||
205 | ci->fscache = fscache_acquire_cookie(fsc->fscache, | 205 | ci->fscache = fscache_acquire_cookie(fsc->fscache, |
206 | &ceph_fscache_inode_object_def, | 206 | &ceph_fscache_inode_object_def, |
207 | ci); | 207 | ci, true); |
208 | done: | 208 | done: |
209 | mutex_unlock(&inode->i_mutex); | 209 | mutex_unlock(&inode->i_mutex); |
210 | 210 | ||
diff --git a/fs/cifs/fscache.c b/fs/cifs/fscache.c index b3258f35e88a..8d4b7bc8ae91 100644 --- a/fs/cifs/fscache.c +++ b/fs/cifs/fscache.c | |||
@@ -27,7 +27,7 @@ void cifs_fscache_get_client_cookie(struct TCP_Server_Info *server) | |||
27 | { | 27 | { |
28 | server->fscache = | 28 | server->fscache = |
29 | fscache_acquire_cookie(cifs_fscache_netfs.primary_index, | 29 | fscache_acquire_cookie(cifs_fscache_netfs.primary_index, |
30 | &cifs_fscache_server_index_def, server); | 30 | &cifs_fscache_server_index_def, server, true); |
31 | cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", | 31 | cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", |
32 | __func__, server, server->fscache); | 32 | __func__, server, server->fscache); |
33 | } | 33 | } |
@@ -46,7 +46,7 @@ void cifs_fscache_get_super_cookie(struct cifs_tcon *tcon) | |||
46 | 46 | ||
47 | tcon->fscache = | 47 | tcon->fscache = |
48 | fscache_acquire_cookie(server->fscache, | 48 | fscache_acquire_cookie(server->fscache, |
49 | &cifs_fscache_super_index_def, tcon); | 49 | &cifs_fscache_super_index_def, tcon, true); |
50 | cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", | 50 | cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", |
51 | __func__, server->fscache, tcon->fscache); | 51 | __func__, server->fscache, tcon->fscache); |
52 | } | 52 | } |
@@ -69,7 +69,7 @@ static void cifs_fscache_enable_inode_cookie(struct inode *inode) | |||
69 | 69 | ||
70 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE) { | 70 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE) { |
71 | cifsi->fscache = fscache_acquire_cookie(tcon->fscache, | 71 | cifsi->fscache = fscache_acquire_cookie(tcon->fscache, |
72 | &cifs_fscache_inode_object_def, cifsi); | 72 | &cifs_fscache_inode_object_def, cifsi, true); |
73 | cifs_dbg(FYI, "%s: got FH cookie (0x%p/0x%p)\n", | 73 | cifs_dbg(FYI, "%s: got FH cookie (0x%p/0x%p)\n", |
74 | __func__, tcon->fscache, cifsi->fscache); | 74 | __func__, tcon->fscache, cifsi->fscache); |
75 | } | 75 | } |
@@ -119,7 +119,7 @@ void cifs_fscache_reset_inode_cookie(struct inode *inode) | |||
119 | cifsi->fscache = fscache_acquire_cookie( | 119 | cifsi->fscache = fscache_acquire_cookie( |
120 | cifs_sb_master_tcon(cifs_sb)->fscache, | 120 | cifs_sb_master_tcon(cifs_sb)->fscache, |
121 | &cifs_fscache_inode_object_def, | 121 | &cifs_fscache_inode_object_def, |
122 | cifsi); | 122 | cifsi, true); |
123 | cifs_dbg(FYI, "%s: new cookie 0x%p oldcookie 0x%p\n", | 123 | cifs_dbg(FYI, "%s: new cookie 0x%p oldcookie 0x%p\n", |
124 | __func__, cifsi->fscache, old); | 124 | __func__, cifsi->fscache, old); |
125 | } | 125 | } |
diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c index b2a86e324aac..29d7feb62cf7 100644 --- a/fs/fscache/cookie.c +++ b/fs/fscache/cookie.c | |||
@@ -58,15 +58,16 @@ void fscache_cookie_init_once(void *_cookie) | |||
58 | struct fscache_cookie *__fscache_acquire_cookie( | 58 | struct fscache_cookie *__fscache_acquire_cookie( |
59 | struct fscache_cookie *parent, | 59 | struct fscache_cookie *parent, |
60 | const struct fscache_cookie_def *def, | 60 | const struct fscache_cookie_def *def, |
61 | void *netfs_data) | 61 | void *netfs_data, |
62 | bool enable) | ||
62 | { | 63 | { |
63 | struct fscache_cookie *cookie; | 64 | struct fscache_cookie *cookie; |
64 | 65 | ||
65 | BUG_ON(!def); | 66 | BUG_ON(!def); |
66 | 67 | ||
67 | _enter("{%s},{%s},%p", | 68 | _enter("{%s},{%s},%p,%u", |
68 | parent ? (char *) parent->def->name : "<no-parent>", | 69 | parent ? (char *) parent->def->name : "<no-parent>", |
69 | def->name, netfs_data); | 70 | def->name, netfs_data, enable); |
70 | 71 | ||
71 | fscache_stat(&fscache_n_acquires); | 72 | fscache_stat(&fscache_n_acquires); |
72 | 73 | ||
@@ -106,7 +107,7 @@ struct fscache_cookie *__fscache_acquire_cookie( | |||
106 | cookie->def = def; | 107 | cookie->def = def; |
107 | cookie->parent = parent; | 108 | cookie->parent = parent; |
108 | cookie->netfs_data = netfs_data; | 109 | cookie->netfs_data = netfs_data; |
109 | cookie->flags = 0; | 110 | cookie->flags = (1 << FSCACHE_COOKIE_NO_DATA_YET); |
110 | 111 | ||
111 | /* radix tree insertion won't use the preallocation pool unless it's | 112 | /* radix tree insertion won't use the preallocation pool unless it's |
112 | * told it may not wait */ | 113 | * told it may not wait */ |
@@ -124,16 +125,22 @@ struct fscache_cookie *__fscache_acquire_cookie( | |||
124 | break; | 125 | break; |
125 | } | 126 | } |
126 | 127 | ||
127 | /* if the object is an index then we need do nothing more here - we | 128 | if (enable) { |
128 | * create indices on disk when we need them as an index may exist in | 129 | /* if the object is an index then we need do nothing more here |
129 | * multiple caches */ | 130 | * - we create indices on disk when we need them as an index |
130 | if (cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX) { | 131 | * may exist in multiple caches */ |
131 | if (fscache_acquire_non_index_cookie(cookie) < 0) { | 132 | if (cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX) { |
132 | atomic_dec(&parent->n_children); | 133 | if (fscache_acquire_non_index_cookie(cookie) == 0) { |
133 | __fscache_cookie_put(cookie); | 134 | set_bit(FSCACHE_COOKIE_ENABLED, &cookie->flags); |
134 | fscache_stat(&fscache_n_acquires_nobufs); | 135 | } else { |
135 | _leave(" = NULL"); | 136 | atomic_dec(&parent->n_children); |
136 | return NULL; | 137 | __fscache_cookie_put(cookie); |
138 | fscache_stat(&fscache_n_acquires_nobufs); | ||
139 | _leave(" = NULL"); | ||
140 | return NULL; | ||
141 | } | ||
142 | } else { | ||
143 | set_bit(FSCACHE_COOKIE_ENABLED, &cookie->flags); | ||
137 | } | 144 | } |
138 | } | 145 | } |
139 | 146 | ||
@@ -144,6 +151,39 @@ struct fscache_cookie *__fscache_acquire_cookie( | |||
144 | EXPORT_SYMBOL(__fscache_acquire_cookie); | 151 | EXPORT_SYMBOL(__fscache_acquire_cookie); |
145 | 152 | ||
146 | /* | 153 | /* |
154 | * Enable a cookie to permit it to accept new operations. | ||
155 | */ | ||
156 | void __fscache_enable_cookie(struct fscache_cookie *cookie, | ||
157 | bool (*can_enable)(void *data), | ||
158 | void *data) | ||
159 | { | ||
160 | _enter("%p", cookie); | ||
161 | |||
162 | wait_on_bit_lock(&cookie->flags, FSCACHE_COOKIE_ENABLEMENT_LOCK, | ||
163 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); | ||
164 | |||
165 | if (test_bit(FSCACHE_COOKIE_ENABLED, &cookie->flags)) | ||
166 | goto out_unlock; | ||
167 | |||
168 | if (can_enable && !can_enable(data)) { | ||
169 | /* The netfs decided it didn't want to enable after all */ | ||
170 | } else if (cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX) { | ||
171 | /* Wait for outstanding disablement to complete */ | ||
172 | __fscache_wait_on_invalidate(cookie); | ||
173 | |||
174 | if (fscache_acquire_non_index_cookie(cookie) == 0) | ||
175 | set_bit(FSCACHE_COOKIE_ENABLED, &cookie->flags); | ||
176 | } else { | ||
177 | set_bit(FSCACHE_COOKIE_ENABLED, &cookie->flags); | ||
178 | } | ||
179 | |||
180 | out_unlock: | ||
181 | clear_bit_unlock(FSCACHE_COOKIE_ENABLEMENT_LOCK, &cookie->flags); | ||
182 | wake_up_bit(&cookie->flags, FSCACHE_COOKIE_ENABLEMENT_LOCK); | ||
183 | } | ||
184 | EXPORT_SYMBOL(__fscache_enable_cookie); | ||
185 | |||
186 | /* | ||
147 | * acquire a non-index cookie | 187 | * acquire a non-index cookie |
148 | * - this must make sure the index chain is instantiated and instantiate the | 188 | * - this must make sure the index chain is instantiated and instantiate the |
149 | * object representation too | 189 | * object representation too |
@@ -157,7 +197,7 @@ static int fscache_acquire_non_index_cookie(struct fscache_cookie *cookie) | |||
157 | 197 | ||
158 | _enter(""); | 198 | _enter(""); |
159 | 199 | ||
160 | cookie->flags = 1 << FSCACHE_COOKIE_UNAVAILABLE; | 200 | set_bit(FSCACHE_COOKIE_UNAVAILABLE, &cookie->flags); |
161 | 201 | ||
162 | /* now we need to see whether the backing objects for this cookie yet | 202 | /* now we need to see whether the backing objects for this cookie yet |
163 | * exist, if not there'll be nothing to search */ | 203 | * exist, if not there'll be nothing to search */ |
@@ -180,9 +220,7 @@ static int fscache_acquire_non_index_cookie(struct fscache_cookie *cookie) | |||
180 | 220 | ||
181 | _debug("cache %s", cache->tag->name); | 221 | _debug("cache %s", cache->tag->name); |
182 | 222 | ||
183 | cookie->flags = | 223 | set_bit(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags); |
184 | (1 << FSCACHE_COOKIE_LOOKING_UP) | | ||
185 | (1 << FSCACHE_COOKIE_NO_DATA_YET); | ||
186 | 224 | ||
187 | /* ask the cache to allocate objects for this cookie and its parent | 225 | /* ask the cache to allocate objects for this cookie and its parent |
188 | * chain */ | 226 | * chain */ |
@@ -398,7 +436,8 @@ void __fscache_invalidate(struct fscache_cookie *cookie) | |||
398 | if (!hlist_empty(&cookie->backing_objects)) { | 436 | if (!hlist_empty(&cookie->backing_objects)) { |
399 | spin_lock(&cookie->lock); | 437 | spin_lock(&cookie->lock); |
400 | 438 | ||
401 | if (!hlist_empty(&cookie->backing_objects) && | 439 | if (fscache_cookie_enabled(cookie) && |
440 | !hlist_empty(&cookie->backing_objects) && | ||
402 | !test_and_set_bit(FSCACHE_COOKIE_INVALIDATING, | 441 | !test_and_set_bit(FSCACHE_COOKIE_INVALIDATING, |
403 | &cookie->flags)) { | 442 | &cookie->flags)) { |
404 | object = hlist_entry(cookie->backing_objects.first, | 443 | object = hlist_entry(cookie->backing_objects.first, |
@@ -452,10 +491,14 @@ void __fscache_update_cookie(struct fscache_cookie *cookie) | |||
452 | 491 | ||
453 | spin_lock(&cookie->lock); | 492 | spin_lock(&cookie->lock); |
454 | 493 | ||
455 | /* update the index entry on disk in each cache backing this cookie */ | 494 | if (fscache_cookie_enabled(cookie)) { |
456 | hlist_for_each_entry(object, | 495 | /* update the index entry on disk in each cache backing this |
457 | &cookie->backing_objects, cookie_link) { | 496 | * cookie. |
458 | fscache_raise_event(object, FSCACHE_OBJECT_EV_UPDATE); | 497 | */ |
498 | hlist_for_each_entry(object, | ||
499 | &cookie->backing_objects, cookie_link) { | ||
500 | fscache_raise_event(object, FSCACHE_OBJECT_EV_UPDATE); | ||
501 | } | ||
459 | } | 502 | } |
460 | 503 | ||
461 | spin_unlock(&cookie->lock); | 504 | spin_unlock(&cookie->lock); |
@@ -464,28 +507,14 @@ void __fscache_update_cookie(struct fscache_cookie *cookie) | |||
464 | EXPORT_SYMBOL(__fscache_update_cookie); | 507 | EXPORT_SYMBOL(__fscache_update_cookie); |
465 | 508 | ||
466 | /* | 509 | /* |
467 | * release a cookie back to the cache | 510 | * Disable a cookie to stop it from accepting new requests from the netfs. |
468 | * - the object will be marked as recyclable on disk if retire is true | ||
469 | * - all dependents of this cookie must have already been unregistered | ||
470 | * (indices/files/pages) | ||
471 | */ | 511 | */ |
472 | void __fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire) | 512 | void __fscache_disable_cookie(struct fscache_cookie *cookie, bool invalidate) |
473 | { | 513 | { |
474 | struct fscache_object *object; | 514 | struct fscache_object *object; |
515 | bool awaken = false; | ||
475 | 516 | ||
476 | fscache_stat(&fscache_n_relinquishes); | 517 | _enter("%p,%u", cookie, invalidate); |
477 | if (retire) | ||
478 | fscache_stat(&fscache_n_relinquishes_retire); | ||
479 | |||
480 | if (!cookie) { | ||
481 | fscache_stat(&fscache_n_relinquishes_null); | ||
482 | _leave(" [no cookie]"); | ||
483 | return; | ||
484 | } | ||
485 | |||
486 | _enter("%p{%s,%p,%d},%d", | ||
487 | cookie, cookie->def->name, cookie->netfs_data, | ||
488 | atomic_read(&cookie->n_active), retire); | ||
489 | 518 | ||
490 | ASSERTCMP(atomic_read(&cookie->n_active), >, 0); | 519 | ASSERTCMP(atomic_read(&cookie->n_active), >, 0); |
491 | 520 | ||
@@ -495,24 +524,82 @@ void __fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire) | |||
495 | BUG(); | 524 | BUG(); |
496 | } | 525 | } |
497 | 526 | ||
498 | /* No further netfs-accessing operations on this cookie permitted */ | 527 | wait_on_bit_lock(&cookie->flags, FSCACHE_COOKIE_ENABLEMENT_LOCK, |
499 | set_bit(FSCACHE_COOKIE_RELINQUISHED, &cookie->flags); | 528 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); |
500 | if (retire) | 529 | if (!test_and_clear_bit(FSCACHE_COOKIE_ENABLED, &cookie->flags)) |
501 | set_bit(FSCACHE_COOKIE_RETIRED, &cookie->flags); | 530 | goto out_unlock_enable; |
531 | |||
532 | /* If the cookie is being invalidated, wait for that to complete first | ||
533 | * so that we can reuse the flag. | ||
534 | */ | ||
535 | __fscache_wait_on_invalidate(cookie); | ||
536 | |||
537 | /* Dispose of the backing objects */ | ||
538 | set_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags); | ||
502 | 539 | ||
503 | spin_lock(&cookie->lock); | 540 | spin_lock(&cookie->lock); |
504 | hlist_for_each_entry(object, &cookie->backing_objects, cookie_link) { | 541 | if (!hlist_empty(&cookie->backing_objects)) { |
505 | fscache_raise_event(object, FSCACHE_OBJECT_EV_KILL); | 542 | hlist_for_each_entry(object, &cookie->backing_objects, cookie_link) { |
543 | if (invalidate) | ||
544 | set_bit(FSCACHE_OBJECT_RETIRED, &object->flags); | ||
545 | fscache_raise_event(object, FSCACHE_OBJECT_EV_KILL); | ||
546 | } | ||
547 | } else { | ||
548 | if (test_and_clear_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) | ||
549 | awaken = true; | ||
506 | } | 550 | } |
507 | spin_unlock(&cookie->lock); | 551 | spin_unlock(&cookie->lock); |
552 | if (awaken) | ||
553 | wake_up_bit(&cookie->flags, FSCACHE_COOKIE_INVALIDATING); | ||
508 | 554 | ||
509 | /* Wait for cessation of activity requiring access to the netfs (when | 555 | /* Wait for cessation of activity requiring access to the netfs (when |
510 | * n_active reaches 0). | 556 | * n_active reaches 0). This makes sure outstanding reads and writes |
557 | * have completed. | ||
511 | */ | 558 | */ |
512 | if (!atomic_dec_and_test(&cookie->n_active)) | 559 | if (!atomic_dec_and_test(&cookie->n_active)) |
513 | wait_on_atomic_t(&cookie->n_active, fscache_wait_atomic_t, | 560 | wait_on_atomic_t(&cookie->n_active, fscache_wait_atomic_t, |
514 | TASK_UNINTERRUPTIBLE); | 561 | TASK_UNINTERRUPTIBLE); |
515 | 562 | ||
563 | /* Reset the cookie state if it wasn't relinquished */ | ||
564 | if (!test_bit(FSCACHE_COOKIE_RELINQUISHED, &cookie->flags)) { | ||
565 | atomic_inc(&cookie->n_active); | ||
566 | set_bit(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags); | ||
567 | } | ||
568 | |||
569 | out_unlock_enable: | ||
570 | clear_bit_unlock(FSCACHE_COOKIE_ENABLEMENT_LOCK, &cookie->flags); | ||
571 | wake_up_bit(&cookie->flags, FSCACHE_COOKIE_ENABLEMENT_LOCK); | ||
572 | _leave(""); | ||
573 | } | ||
574 | EXPORT_SYMBOL(__fscache_disable_cookie); | ||
575 | |||
576 | /* | ||
577 | * release a cookie back to the cache | ||
578 | * - the object will be marked as recyclable on disk if retire is true | ||
579 | * - all dependents of this cookie must have already been unregistered | ||
580 | * (indices/files/pages) | ||
581 | */ | ||
582 | void __fscache_relinquish_cookie(struct fscache_cookie *cookie, bool retire) | ||
583 | { | ||
584 | fscache_stat(&fscache_n_relinquishes); | ||
585 | if (retire) | ||
586 | fscache_stat(&fscache_n_relinquishes_retire); | ||
587 | |||
588 | if (!cookie) { | ||
589 | fscache_stat(&fscache_n_relinquishes_null); | ||
590 | _leave(" [no cookie]"); | ||
591 | return; | ||
592 | } | ||
593 | |||
594 | _enter("%p{%s,%p,%d},%d", | ||
595 | cookie, cookie->def->name, cookie->netfs_data, | ||
596 | atomic_read(&cookie->n_active), retire); | ||
597 | |||
598 | /* No further netfs-accessing operations on this cookie permitted */ | ||
599 | set_bit(FSCACHE_COOKIE_RELINQUISHED, &cookie->flags); | ||
600 | |||
601 | __fscache_disable_cookie(cookie, retire); | ||
602 | |||
516 | /* Clear pointers back to the netfs */ | 603 | /* Clear pointers back to the netfs */ |
517 | cookie->netfs_data = NULL; | 604 | cookie->netfs_data = NULL; |
518 | cookie->def = NULL; | 605 | cookie->def = NULL; |
@@ -568,6 +655,7 @@ int __fscache_check_consistency(struct fscache_cookie *cookie) | |||
568 | { | 655 | { |
569 | struct fscache_operation *op; | 656 | struct fscache_operation *op; |
570 | struct fscache_object *object; | 657 | struct fscache_object *object; |
658 | bool wake_cookie = false; | ||
571 | int ret; | 659 | int ret; |
572 | 660 | ||
573 | _enter("%p,", cookie); | 661 | _enter("%p,", cookie); |
@@ -591,7 +679,8 @@ int __fscache_check_consistency(struct fscache_cookie *cookie) | |||
591 | 679 | ||
592 | spin_lock(&cookie->lock); | 680 | spin_lock(&cookie->lock); |
593 | 681 | ||
594 | if (hlist_empty(&cookie->backing_objects)) | 682 | if (!fscache_cookie_enabled(cookie) || |
683 | hlist_empty(&cookie->backing_objects)) | ||
595 | goto inconsistent; | 684 | goto inconsistent; |
596 | object = hlist_entry(cookie->backing_objects.first, | 685 | object = hlist_entry(cookie->backing_objects.first, |
597 | struct fscache_object, cookie_link); | 686 | struct fscache_object, cookie_link); |
@@ -600,7 +689,7 @@ int __fscache_check_consistency(struct fscache_cookie *cookie) | |||
600 | 689 | ||
601 | op->debug_id = atomic_inc_return(&fscache_op_debug_id); | 690 | op->debug_id = atomic_inc_return(&fscache_op_debug_id); |
602 | 691 | ||
603 | atomic_inc(&cookie->n_active); | 692 | __fscache_use_cookie(cookie); |
604 | if (fscache_submit_op(object, op) < 0) | 693 | if (fscache_submit_op(object, op) < 0) |
605 | goto submit_failed; | 694 | goto submit_failed; |
606 | 695 | ||
@@ -622,9 +711,11 @@ int __fscache_check_consistency(struct fscache_cookie *cookie) | |||
622 | return ret; | 711 | return ret; |
623 | 712 | ||
624 | submit_failed: | 713 | submit_failed: |
625 | atomic_dec(&cookie->n_active); | 714 | wake_cookie = __fscache_unuse_cookie(cookie); |
626 | inconsistent: | 715 | inconsistent: |
627 | spin_unlock(&cookie->lock); | 716 | spin_unlock(&cookie->lock); |
717 | if (wake_cookie) | ||
718 | __fscache_wake_unused_cookie(cookie); | ||
628 | kfree(op); | 719 | kfree(op); |
629 | _leave(" = -ESTALE"); | 720 | _leave(" = -ESTALE"); |
630 | return -ESTALE; | 721 | return -ESTALE; |
diff --git a/fs/fscache/fsdef.c b/fs/fscache/fsdef.c index 10a2ade0bdf8..5a117df2a9ef 100644 --- a/fs/fscache/fsdef.c +++ b/fs/fscache/fsdef.c | |||
@@ -59,6 +59,7 @@ struct fscache_cookie fscache_fsdef_index = { | |||
59 | .lock = __SPIN_LOCK_UNLOCKED(fscache_fsdef_index.lock), | 59 | .lock = __SPIN_LOCK_UNLOCKED(fscache_fsdef_index.lock), |
60 | .backing_objects = HLIST_HEAD_INIT, | 60 | .backing_objects = HLIST_HEAD_INIT, |
61 | .def = &fscache_fsdef_index_def, | 61 | .def = &fscache_fsdef_index_def, |
62 | .flags = 1 << FSCACHE_COOKIE_ENABLED, | ||
62 | }; | 63 | }; |
63 | EXPORT_SYMBOL(fscache_fsdef_index); | 64 | EXPORT_SYMBOL(fscache_fsdef_index); |
64 | 65 | ||
diff --git a/fs/fscache/netfs.c b/fs/fscache/netfs.c index b1bb6117473a..989f39401547 100644 --- a/fs/fscache/netfs.c +++ b/fs/fscache/netfs.c | |||
@@ -45,6 +45,7 @@ int __fscache_register_netfs(struct fscache_netfs *netfs) | |||
45 | netfs->primary_index->def = &fscache_fsdef_netfs_def; | 45 | netfs->primary_index->def = &fscache_fsdef_netfs_def; |
46 | netfs->primary_index->parent = &fscache_fsdef_index; | 46 | netfs->primary_index->parent = &fscache_fsdef_index; |
47 | netfs->primary_index->netfs_data = netfs; | 47 | netfs->primary_index->netfs_data = netfs; |
48 | netfs->primary_index->flags = 1 << FSCACHE_COOKIE_ENABLED; | ||
48 | 49 | ||
49 | atomic_inc(&netfs->primary_index->parent->usage); | 50 | atomic_inc(&netfs->primary_index->parent->usage); |
50 | atomic_inc(&netfs->primary_index->parent->n_children); | 51 | atomic_inc(&netfs->primary_index->parent->n_children); |
diff --git a/fs/fscache/object.c b/fs/fscache/object.c index 86d75a60b20c..dcb821617774 100644 --- a/fs/fscache/object.c +++ b/fs/fscache/object.c | |||
@@ -495,6 +495,7 @@ void fscache_object_lookup_negative(struct fscache_object *object) | |||
495 | * returning ENODATA. | 495 | * returning ENODATA. |
496 | */ | 496 | */ |
497 | set_bit(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags); | 497 | set_bit(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags); |
498 | clear_bit(FSCACHE_COOKIE_UNAVAILABLE, &cookie->flags); | ||
498 | 499 | ||
499 | _debug("wake up lookup %p", &cookie->flags); | 500 | _debug("wake up lookup %p", &cookie->flags); |
500 | clear_bit_unlock(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags); | 501 | clear_bit_unlock(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags); |
@@ -527,6 +528,7 @@ void fscache_obtained_object(struct fscache_object *object) | |||
527 | 528 | ||
528 | /* We do (presumably) have data */ | 529 | /* We do (presumably) have data */ |
529 | clear_bit_unlock(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags); | 530 | clear_bit_unlock(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags); |
531 | clear_bit(FSCACHE_COOKIE_UNAVAILABLE, &cookie->flags); | ||
530 | 532 | ||
531 | /* Allow write requests to begin stacking up and read requests | 533 | /* Allow write requests to begin stacking up and read requests |
532 | * to begin shovelling data. | 534 | * to begin shovelling data. |
@@ -679,7 +681,8 @@ static const struct fscache_state *fscache_drop_object(struct fscache_object *ob | |||
679 | */ | 681 | */ |
680 | spin_lock(&cookie->lock); | 682 | spin_lock(&cookie->lock); |
681 | hlist_del_init(&object->cookie_link); | 683 | hlist_del_init(&object->cookie_link); |
682 | if (test_and_clear_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) | 684 | if (hlist_empty(&cookie->backing_objects) && |
685 | test_and_clear_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) | ||
683 | awaken = true; | 686 | awaken = true; |
684 | spin_unlock(&cookie->lock); | 687 | spin_unlock(&cookie->lock); |
685 | 688 | ||
@@ -927,7 +930,7 @@ static const struct fscache_state *_fscache_invalidate_object(struct fscache_obj | |||
927 | */ | 930 | */ |
928 | if (!fscache_use_cookie(object)) { | 931 | if (!fscache_use_cookie(object)) { |
929 | ASSERT(object->cookie->stores.rnode == NULL); | 932 | ASSERT(object->cookie->stores.rnode == NULL); |
930 | set_bit(FSCACHE_COOKIE_RETIRED, &cookie->flags); | 933 | set_bit(FSCACHE_OBJECT_RETIRED, &object->flags); |
931 | _leave(" [no cookie]"); | 934 | _leave(" [no cookie]"); |
932 | return transit_to(KILL_OBJECT); | 935 | return transit_to(KILL_OBJECT); |
933 | } | 936 | } |
diff --git a/fs/fscache/page.c b/fs/fscache/page.c index 73899c1c3449..7f5c658af755 100644 --- a/fs/fscache/page.c +++ b/fs/fscache/page.c | |||
@@ -163,12 +163,10 @@ static void fscache_attr_changed_op(struct fscache_operation *op) | |||
163 | 163 | ||
164 | fscache_stat(&fscache_n_attr_changed_calls); | 164 | fscache_stat(&fscache_n_attr_changed_calls); |
165 | 165 | ||
166 | if (fscache_object_is_active(object) && | 166 | if (fscache_object_is_active(object)) { |
167 | fscache_use_cookie(object)) { | ||
168 | fscache_stat(&fscache_n_cop_attr_changed); | 167 | fscache_stat(&fscache_n_cop_attr_changed); |
169 | ret = object->cache->ops->attr_changed(object); | 168 | ret = object->cache->ops->attr_changed(object); |
170 | fscache_stat_d(&fscache_n_cop_attr_changed); | 169 | fscache_stat_d(&fscache_n_cop_attr_changed); |
171 | fscache_unuse_cookie(object); | ||
172 | if (ret < 0) | 170 | if (ret < 0) |
173 | fscache_abort_object(object); | 171 | fscache_abort_object(object); |
174 | } | 172 | } |
@@ -184,6 +182,7 @@ int __fscache_attr_changed(struct fscache_cookie *cookie) | |||
184 | { | 182 | { |
185 | struct fscache_operation *op; | 183 | struct fscache_operation *op; |
186 | struct fscache_object *object; | 184 | struct fscache_object *object; |
185 | bool wake_cookie; | ||
187 | 186 | ||
188 | _enter("%p", cookie); | 187 | _enter("%p", cookie); |
189 | 188 | ||
@@ -199,15 +198,19 @@ int __fscache_attr_changed(struct fscache_cookie *cookie) | |||
199 | } | 198 | } |
200 | 199 | ||
201 | fscache_operation_init(op, fscache_attr_changed_op, NULL); | 200 | fscache_operation_init(op, fscache_attr_changed_op, NULL); |
202 | op->flags = FSCACHE_OP_ASYNC | (1 << FSCACHE_OP_EXCLUSIVE); | 201 | op->flags = FSCACHE_OP_ASYNC | |
202 | (1 << FSCACHE_OP_EXCLUSIVE) | | ||
203 | (1 << FSCACHE_OP_UNUSE_COOKIE); | ||
203 | 204 | ||
204 | spin_lock(&cookie->lock); | 205 | spin_lock(&cookie->lock); |
205 | 206 | ||
206 | if (hlist_empty(&cookie->backing_objects)) | 207 | if (!fscache_cookie_enabled(cookie) || |
208 | hlist_empty(&cookie->backing_objects)) | ||
207 | goto nobufs; | 209 | goto nobufs; |
208 | object = hlist_entry(cookie->backing_objects.first, | 210 | object = hlist_entry(cookie->backing_objects.first, |
209 | struct fscache_object, cookie_link); | 211 | struct fscache_object, cookie_link); |
210 | 212 | ||
213 | __fscache_use_cookie(cookie); | ||
211 | if (fscache_submit_exclusive_op(object, op) < 0) | 214 | if (fscache_submit_exclusive_op(object, op) < 0) |
212 | goto nobufs; | 215 | goto nobufs; |
213 | spin_unlock(&cookie->lock); | 216 | spin_unlock(&cookie->lock); |
@@ -217,8 +220,11 @@ int __fscache_attr_changed(struct fscache_cookie *cookie) | |||
217 | return 0; | 220 | return 0; |
218 | 221 | ||
219 | nobufs: | 222 | nobufs: |
223 | wake_cookie = __fscache_unuse_cookie(cookie); | ||
220 | spin_unlock(&cookie->lock); | 224 | spin_unlock(&cookie->lock); |
221 | kfree(op); | 225 | kfree(op); |
226 | if (wake_cookie) | ||
227 | __fscache_wake_unused_cookie(cookie); | ||
222 | fscache_stat(&fscache_n_attr_changed_nobufs); | 228 | fscache_stat(&fscache_n_attr_changed_nobufs); |
223 | _leave(" = %d", -ENOBUFS); | 229 | _leave(" = %d", -ENOBUFS); |
224 | return -ENOBUFS; | 230 | return -ENOBUFS; |
@@ -263,7 +269,6 @@ static struct fscache_retrieval *fscache_alloc_retrieval( | |||
263 | } | 269 | } |
264 | 270 | ||
265 | fscache_operation_init(&op->op, NULL, fscache_release_retrieval_op); | 271 | fscache_operation_init(&op->op, NULL, fscache_release_retrieval_op); |
266 | atomic_inc(&cookie->n_active); | ||
267 | op->op.flags = FSCACHE_OP_MYTHREAD | | 272 | op->op.flags = FSCACHE_OP_MYTHREAD | |
268 | (1UL << FSCACHE_OP_WAITING) | | 273 | (1UL << FSCACHE_OP_WAITING) | |
269 | (1UL << FSCACHE_OP_UNUSE_COOKIE); | 274 | (1UL << FSCACHE_OP_UNUSE_COOKIE); |
@@ -384,6 +389,7 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie, | |||
384 | { | 389 | { |
385 | struct fscache_retrieval *op; | 390 | struct fscache_retrieval *op; |
386 | struct fscache_object *object; | 391 | struct fscache_object *object; |
392 | bool wake_cookie = false; | ||
387 | int ret; | 393 | int ret; |
388 | 394 | ||
389 | _enter("%p,%p,,,", cookie, page); | 395 | _enter("%p,%p,,,", cookie, page); |
@@ -405,7 +411,7 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie, | |||
405 | return -ERESTARTSYS; | 411 | return -ERESTARTSYS; |
406 | 412 | ||
407 | op = fscache_alloc_retrieval(cookie, page->mapping, | 413 | op = fscache_alloc_retrieval(cookie, page->mapping, |
408 | end_io_func,context); | 414 | end_io_func, context); |
409 | if (!op) { | 415 | if (!op) { |
410 | _leave(" = -ENOMEM"); | 416 | _leave(" = -ENOMEM"); |
411 | return -ENOMEM; | 417 | return -ENOMEM; |
@@ -414,13 +420,15 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie, | |||
414 | 420 | ||
415 | spin_lock(&cookie->lock); | 421 | spin_lock(&cookie->lock); |
416 | 422 | ||
417 | if (hlist_empty(&cookie->backing_objects)) | 423 | if (!fscache_cookie_enabled(cookie) || |
424 | hlist_empty(&cookie->backing_objects)) | ||
418 | goto nobufs_unlock; | 425 | goto nobufs_unlock; |
419 | object = hlist_entry(cookie->backing_objects.first, | 426 | object = hlist_entry(cookie->backing_objects.first, |
420 | struct fscache_object, cookie_link); | 427 | struct fscache_object, cookie_link); |
421 | 428 | ||
422 | ASSERT(test_bit(FSCACHE_OBJECT_IS_LOOKED_UP, &object->flags)); | 429 | ASSERT(test_bit(FSCACHE_OBJECT_IS_LOOKED_UP, &object->flags)); |
423 | 430 | ||
431 | __fscache_use_cookie(cookie); | ||
424 | atomic_inc(&object->n_reads); | 432 | atomic_inc(&object->n_reads); |
425 | __set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags); | 433 | __set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags); |
426 | 434 | ||
@@ -475,9 +483,11 @@ error: | |||
475 | 483 | ||
476 | nobufs_unlock_dec: | 484 | nobufs_unlock_dec: |
477 | atomic_dec(&object->n_reads); | 485 | atomic_dec(&object->n_reads); |
486 | wake_cookie = __fscache_unuse_cookie(cookie); | ||
478 | nobufs_unlock: | 487 | nobufs_unlock: |
479 | spin_unlock(&cookie->lock); | 488 | spin_unlock(&cookie->lock); |
480 | atomic_dec(&cookie->n_active); | 489 | if (wake_cookie) |
490 | __fscache_wake_unused_cookie(cookie); | ||
481 | kfree(op); | 491 | kfree(op); |
482 | nobufs: | 492 | nobufs: |
483 | fscache_stat(&fscache_n_retrievals_nobufs); | 493 | fscache_stat(&fscache_n_retrievals_nobufs); |
@@ -514,6 +524,7 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie, | |||
514 | { | 524 | { |
515 | struct fscache_retrieval *op; | 525 | struct fscache_retrieval *op; |
516 | struct fscache_object *object; | 526 | struct fscache_object *object; |
527 | bool wake_cookie = false; | ||
517 | int ret; | 528 | int ret; |
518 | 529 | ||
519 | _enter("%p,,%d,,,", cookie, *nr_pages); | 530 | _enter("%p,,%d,,,", cookie, *nr_pages); |
@@ -542,11 +553,13 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie, | |||
542 | 553 | ||
543 | spin_lock(&cookie->lock); | 554 | spin_lock(&cookie->lock); |
544 | 555 | ||
545 | if (hlist_empty(&cookie->backing_objects)) | 556 | if (!fscache_cookie_enabled(cookie) || |
557 | hlist_empty(&cookie->backing_objects)) | ||
546 | goto nobufs_unlock; | 558 | goto nobufs_unlock; |
547 | object = hlist_entry(cookie->backing_objects.first, | 559 | object = hlist_entry(cookie->backing_objects.first, |
548 | struct fscache_object, cookie_link); | 560 | struct fscache_object, cookie_link); |
549 | 561 | ||
562 | __fscache_use_cookie(cookie); | ||
550 | atomic_inc(&object->n_reads); | 563 | atomic_inc(&object->n_reads); |
551 | __set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags); | 564 | __set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags); |
552 | 565 | ||
@@ -601,10 +614,12 @@ error: | |||
601 | 614 | ||
602 | nobufs_unlock_dec: | 615 | nobufs_unlock_dec: |
603 | atomic_dec(&object->n_reads); | 616 | atomic_dec(&object->n_reads); |
617 | wake_cookie = __fscache_unuse_cookie(cookie); | ||
604 | nobufs_unlock: | 618 | nobufs_unlock: |
605 | spin_unlock(&cookie->lock); | 619 | spin_unlock(&cookie->lock); |
606 | atomic_dec(&cookie->n_active); | ||
607 | kfree(op); | 620 | kfree(op); |
621 | if (wake_cookie) | ||
622 | __fscache_wake_unused_cookie(cookie); | ||
608 | nobufs: | 623 | nobufs: |
609 | fscache_stat(&fscache_n_retrievals_nobufs); | 624 | fscache_stat(&fscache_n_retrievals_nobufs); |
610 | _leave(" = -ENOBUFS"); | 625 | _leave(" = -ENOBUFS"); |
@@ -626,6 +641,7 @@ int __fscache_alloc_page(struct fscache_cookie *cookie, | |||
626 | { | 641 | { |
627 | struct fscache_retrieval *op; | 642 | struct fscache_retrieval *op; |
628 | struct fscache_object *object; | 643 | struct fscache_object *object; |
644 | bool wake_cookie = false; | ||
629 | int ret; | 645 | int ret; |
630 | 646 | ||
631 | _enter("%p,%p,,,", cookie, page); | 647 | _enter("%p,%p,,,", cookie, page); |
@@ -653,13 +669,15 @@ int __fscache_alloc_page(struct fscache_cookie *cookie, | |||
653 | 669 | ||
654 | spin_lock(&cookie->lock); | 670 | spin_lock(&cookie->lock); |
655 | 671 | ||
656 | if (hlist_empty(&cookie->backing_objects)) | 672 | if (!fscache_cookie_enabled(cookie) || |
673 | hlist_empty(&cookie->backing_objects)) | ||
657 | goto nobufs_unlock; | 674 | goto nobufs_unlock; |
658 | object = hlist_entry(cookie->backing_objects.first, | 675 | object = hlist_entry(cookie->backing_objects.first, |
659 | struct fscache_object, cookie_link); | 676 | struct fscache_object, cookie_link); |
660 | 677 | ||
678 | __fscache_use_cookie(cookie); | ||
661 | if (fscache_submit_op(object, &op->op) < 0) | 679 | if (fscache_submit_op(object, &op->op) < 0) |
662 | goto nobufs_unlock; | 680 | goto nobufs_unlock_dec; |
663 | spin_unlock(&cookie->lock); | 681 | spin_unlock(&cookie->lock); |
664 | 682 | ||
665 | fscache_stat(&fscache_n_alloc_ops); | 683 | fscache_stat(&fscache_n_alloc_ops); |
@@ -689,10 +707,13 @@ error: | |||
689 | _leave(" = %d", ret); | 707 | _leave(" = %d", ret); |
690 | return ret; | 708 | return ret; |
691 | 709 | ||
710 | nobufs_unlock_dec: | ||
711 | wake_cookie = __fscache_unuse_cookie(cookie); | ||
692 | nobufs_unlock: | 712 | nobufs_unlock: |
693 | spin_unlock(&cookie->lock); | 713 | spin_unlock(&cookie->lock); |
694 | atomic_dec(&cookie->n_active); | ||
695 | kfree(op); | 714 | kfree(op); |
715 | if (wake_cookie) | ||
716 | __fscache_wake_unused_cookie(cookie); | ||
696 | nobufs: | 717 | nobufs: |
697 | fscache_stat(&fscache_n_allocs_nobufs); | 718 | fscache_stat(&fscache_n_allocs_nobufs); |
698 | _leave(" = -ENOBUFS"); | 719 | _leave(" = -ENOBUFS"); |
@@ -889,6 +910,7 @@ int __fscache_write_page(struct fscache_cookie *cookie, | |||
889 | { | 910 | { |
890 | struct fscache_storage *op; | 911 | struct fscache_storage *op; |
891 | struct fscache_object *object; | 912 | struct fscache_object *object; |
913 | bool wake_cookie = false; | ||
892 | int ret; | 914 | int ret; |
893 | 915 | ||
894 | _enter("%p,%x,", cookie, (u32) page->flags); | 916 | _enter("%p,%x,", cookie, (u32) page->flags); |
@@ -920,7 +942,8 @@ int __fscache_write_page(struct fscache_cookie *cookie, | |||
920 | ret = -ENOBUFS; | 942 | ret = -ENOBUFS; |
921 | spin_lock(&cookie->lock); | 943 | spin_lock(&cookie->lock); |
922 | 944 | ||
923 | if (hlist_empty(&cookie->backing_objects)) | 945 | if (!fscache_cookie_enabled(cookie) || |
946 | hlist_empty(&cookie->backing_objects)) | ||
924 | goto nobufs; | 947 | goto nobufs; |
925 | object = hlist_entry(cookie->backing_objects.first, | 948 | object = hlist_entry(cookie->backing_objects.first, |
926 | struct fscache_object, cookie_link); | 949 | struct fscache_object, cookie_link); |
@@ -957,7 +980,7 @@ int __fscache_write_page(struct fscache_cookie *cookie, | |||
957 | op->op.debug_id = atomic_inc_return(&fscache_op_debug_id); | 980 | op->op.debug_id = atomic_inc_return(&fscache_op_debug_id); |
958 | op->store_limit = object->store_limit; | 981 | op->store_limit = object->store_limit; |
959 | 982 | ||
960 | atomic_inc(&cookie->n_active); | 983 | __fscache_use_cookie(cookie); |
961 | if (fscache_submit_op(object, &op->op) < 0) | 984 | if (fscache_submit_op(object, &op->op) < 0) |
962 | goto submit_failed; | 985 | goto submit_failed; |
963 | 986 | ||
@@ -984,10 +1007,10 @@ already_pending: | |||
984 | return 0; | 1007 | return 0; |
985 | 1008 | ||
986 | submit_failed: | 1009 | submit_failed: |
987 | atomic_dec(&cookie->n_active); | ||
988 | spin_lock(&cookie->stores_lock); | 1010 | spin_lock(&cookie->stores_lock); |
989 | radix_tree_delete(&cookie->stores, page->index); | 1011 | radix_tree_delete(&cookie->stores, page->index); |
990 | spin_unlock(&cookie->stores_lock); | 1012 | spin_unlock(&cookie->stores_lock); |
1013 | wake_cookie = __fscache_unuse_cookie(cookie); | ||
991 | page_cache_release(page); | 1014 | page_cache_release(page); |
992 | ret = -ENOBUFS; | 1015 | ret = -ENOBUFS; |
993 | goto nobufs; | 1016 | goto nobufs; |
@@ -999,6 +1022,8 @@ nobufs: | |||
999 | spin_unlock(&cookie->lock); | 1022 | spin_unlock(&cookie->lock); |
1000 | radix_tree_preload_end(); | 1023 | radix_tree_preload_end(); |
1001 | kfree(op); | 1024 | kfree(op); |
1025 | if (wake_cookie) | ||
1026 | __fscache_wake_unused_cookie(cookie); | ||
1002 | fscache_stat(&fscache_n_stores_nobufs); | 1027 | fscache_stat(&fscache_n_stores_nobufs); |
1003 | _leave(" = -ENOBUFS"); | 1028 | _leave(" = -ENOBUFS"); |
1004 | return -ENOBUFS; | 1029 | return -ENOBUFS; |
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig index b5e80b0af315..38c1768b4142 100644 --- a/fs/nfs/Kconfig +++ b/fs/nfs/Kconfig | |||
@@ -140,6 +140,17 @@ config NFS_V4_1_IMPLEMENTATION_ID_DOMAIN | |||
140 | If the NFS client is unchanged from the upstream kernel, this | 140 | If the NFS client is unchanged from the upstream kernel, this |
141 | option should be set to the default "kernel.org". | 141 | option should be set to the default "kernel.org". |
142 | 142 | ||
143 | config NFS_V4_1_MIGRATION | ||
144 | bool "NFSv4.1 client support for migration" | ||
145 | depends on NFS_V4_1 | ||
146 | default n | ||
147 | help | ||
148 | This option makes the NFS client advertise to NFSv4.1 servers that | ||
149 | it can support NFSv4 migration. | ||
150 | |||
151 | The NFSv4.1 pieces of the Linux NFSv4 migration implementation are | ||
152 | still experimental. If you are not an NFSv4 developer, say N here. | ||
153 | |||
143 | config NFS_V4_SECURITY_LABEL | 154 | config NFS_V4_SECURITY_LABEL |
144 | bool | 155 | bool |
145 | depends on NFS_V4_2 && SECURITY | 156 | depends on NFS_V4_2 && SECURITY |
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 67cd73213168..073b4cf67ed9 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -164,8 +164,7 @@ nfs41_callback_up(struct svc_serv *serv) | |||
164 | svc_xprt_put(serv->sv_bc_xprt); | 164 | svc_xprt_put(serv->sv_bc_xprt); |
165 | serv->sv_bc_xprt = NULL; | 165 | serv->sv_bc_xprt = NULL; |
166 | } | 166 | } |
167 | dprintk("--> %s return %ld\n", __func__, | 167 | dprintk("--> %s return %d\n", __func__, PTR_ERR_OR_ZERO(rqstp)); |
168 | IS_ERR(rqstp) ? PTR_ERR(rqstp) : 0); | ||
169 | return rqstp; | 168 | return rqstp; |
170 | } | 169 | } |
171 | 170 | ||
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 2dceee4db076..1d09289c8f0e 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -590,6 +590,8 @@ int nfs_create_rpc_client(struct nfs_client *clp, | |||
590 | 590 | ||
591 | if (test_bit(NFS_CS_DISCRTRY, &clp->cl_flags)) | 591 | if (test_bit(NFS_CS_DISCRTRY, &clp->cl_flags)) |
592 | args.flags |= RPC_CLNT_CREATE_DISCRTRY; | 592 | args.flags |= RPC_CLNT_CREATE_DISCRTRY; |
593 | if (test_bit(NFS_CS_NO_RETRANS_TIMEOUT, &clp->cl_flags)) | ||
594 | args.flags |= RPC_CLNT_CREATE_NO_RETRANS_TIMEOUT; | ||
593 | if (test_bit(NFS_CS_NORESVPORT, &clp->cl_flags)) | 595 | if (test_bit(NFS_CS_NORESVPORT, &clp->cl_flags)) |
594 | args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; | 596 | args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; |
595 | if (test_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags)) | 597 | if (test_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags)) |
@@ -784,8 +786,10 @@ static int nfs_init_server(struct nfs_server *server, | |||
784 | goto error; | 786 | goto error; |
785 | 787 | ||
786 | server->port = data->nfs_server.port; | 788 | server->port = data->nfs_server.port; |
789 | server->auth_info = data->auth_info; | ||
787 | 790 | ||
788 | error = nfs_init_server_rpcclient(server, &timeparms, data->auth_flavors[0]); | 791 | error = nfs_init_server_rpcclient(server, &timeparms, |
792 | data->selected_flavor); | ||
789 | if (error < 0) | 793 | if (error < 0) |
790 | goto error; | 794 | goto error; |
791 | 795 | ||
@@ -926,6 +930,7 @@ void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *sour | |||
926 | target->acdirmax = source->acdirmax; | 930 | target->acdirmax = source->acdirmax; |
927 | target->caps = source->caps; | 931 | target->caps = source->caps; |
928 | target->options = source->options; | 932 | target->options = source->options; |
933 | target->auth_info = source->auth_info; | ||
929 | } | 934 | } |
930 | EXPORT_SYMBOL_GPL(nfs_server_copy_userdata); | 935 | EXPORT_SYMBOL_GPL(nfs_server_copy_userdata); |
931 | 936 | ||
@@ -943,7 +948,7 @@ void nfs_server_insert_lists(struct nfs_server *server) | |||
943 | } | 948 | } |
944 | EXPORT_SYMBOL_GPL(nfs_server_insert_lists); | 949 | EXPORT_SYMBOL_GPL(nfs_server_insert_lists); |
945 | 950 | ||
946 | static void nfs_server_remove_lists(struct nfs_server *server) | 951 | void nfs_server_remove_lists(struct nfs_server *server) |
947 | { | 952 | { |
948 | struct nfs_client *clp = server->nfs_client; | 953 | struct nfs_client *clp = server->nfs_client; |
949 | struct nfs_net *nn; | 954 | struct nfs_net *nn; |
@@ -960,6 +965,7 @@ static void nfs_server_remove_lists(struct nfs_server *server) | |||
960 | 965 | ||
961 | synchronize_rcu(); | 966 | synchronize_rcu(); |
962 | } | 967 | } |
968 | EXPORT_SYMBOL_GPL(nfs_server_remove_lists); | ||
963 | 969 | ||
964 | /* | 970 | /* |
965 | * Allocate and initialise a server record | 971 | * Allocate and initialise a server record |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 02b0df769e2d..9a8676f33350 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -1139,7 +1139,13 @@ out_zap_parent: | |||
1139 | if (inode && S_ISDIR(inode->i_mode)) { | 1139 | if (inode && S_ISDIR(inode->i_mode)) { |
1140 | /* Purge readdir caches. */ | 1140 | /* Purge readdir caches. */ |
1141 | nfs_zap_caches(inode); | 1141 | nfs_zap_caches(inode); |
1142 | if (dentry->d_flags & DCACHE_DISCONNECTED) | 1142 | /* |
1143 | * We can't d_drop the root of a disconnected tree: | ||
1144 | * its d_hash is on the s_anon list and d_drop() would hide | ||
1145 | * it from shrink_dcache_for_unmount(), leading to busy | ||
1146 | * inodes on unmount and further oopses. | ||
1147 | */ | ||
1148 | if (IS_ROOT(dentry)) | ||
1143 | goto out_valid; | 1149 | goto out_valid; |
1144 | } | 1150 | } |
1145 | /* If we have submounts, don't unhash ! */ | 1151 | /* If we have submounts, don't unhash ! */ |
@@ -1381,7 +1387,7 @@ static struct nfs_open_context *create_nfs_open_context(struct dentry *dentry, i | |||
1381 | 1387 | ||
1382 | static int do_open(struct inode *inode, struct file *filp) | 1388 | static int do_open(struct inode *inode, struct file *filp) |
1383 | { | 1389 | { |
1384 | nfs_fscache_set_inode_cookie(inode, filp); | 1390 | nfs_fscache_open_file(inode, filp); |
1385 | return 0; | 1391 | return 0; |
1386 | } | 1392 | } |
1387 | 1393 | ||
diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c index 24d1d1c5fcaf..3ef01f0ba0bc 100644 --- a/fs/nfs/fscache.c +++ b/fs/nfs/fscache.c | |||
@@ -39,7 +39,7 @@ void nfs_fscache_get_client_cookie(struct nfs_client *clp) | |||
39 | /* create a cache index for looking up filehandles */ | 39 | /* create a cache index for looking up filehandles */ |
40 | clp->fscache = fscache_acquire_cookie(nfs_fscache_netfs.primary_index, | 40 | clp->fscache = fscache_acquire_cookie(nfs_fscache_netfs.primary_index, |
41 | &nfs_fscache_server_index_def, | 41 | &nfs_fscache_server_index_def, |
42 | clp); | 42 | clp, true); |
43 | dfprintk(FSCACHE, "NFS: get client cookie (0x%p/0x%p)\n", | 43 | dfprintk(FSCACHE, "NFS: get client cookie (0x%p/0x%p)\n", |
44 | clp, clp->fscache); | 44 | clp, clp->fscache); |
45 | } | 45 | } |
@@ -139,7 +139,7 @@ void nfs_fscache_get_super_cookie(struct super_block *sb, const char *uniq, int | |||
139 | /* create a cache index for looking up filehandles */ | 139 | /* create a cache index for looking up filehandles */ |
140 | nfss->fscache = fscache_acquire_cookie(nfss->nfs_client->fscache, | 140 | nfss->fscache = fscache_acquire_cookie(nfss->nfs_client->fscache, |
141 | &nfs_fscache_super_index_def, | 141 | &nfs_fscache_super_index_def, |
142 | nfss); | 142 | nfss, true); |
143 | dfprintk(FSCACHE, "NFS: get superblock cookie (0x%p/0x%p)\n", | 143 | dfprintk(FSCACHE, "NFS: get superblock cookie (0x%p/0x%p)\n", |
144 | nfss, nfss->fscache); | 144 | nfss, nfss->fscache); |
145 | return; | 145 | return; |
@@ -178,163 +178,79 @@ void nfs_fscache_release_super_cookie(struct super_block *sb) | |||
178 | /* | 178 | /* |
179 | * Initialise the per-inode cache cookie pointer for an NFS inode. | 179 | * Initialise the per-inode cache cookie pointer for an NFS inode. |
180 | */ | 180 | */ |
181 | void nfs_fscache_init_inode_cookie(struct inode *inode) | 181 | void nfs_fscache_init_inode(struct inode *inode) |
182 | { | 182 | { |
183 | NFS_I(inode)->fscache = NULL; | ||
184 | if (S_ISREG(inode->i_mode)) | ||
185 | set_bit(NFS_INO_FSCACHE, &NFS_I(inode)->flags); | ||
186 | } | ||
187 | |||
188 | /* | ||
189 | * Get the per-inode cache cookie for an NFS inode. | ||
190 | */ | ||
191 | static void nfs_fscache_enable_inode_cookie(struct inode *inode) | ||
192 | { | ||
193 | struct super_block *sb = inode->i_sb; | ||
194 | struct nfs_inode *nfsi = NFS_I(inode); | 183 | struct nfs_inode *nfsi = NFS_I(inode); |
195 | 184 | ||
196 | if (nfsi->fscache || !NFS_FSCACHE(inode)) | 185 | nfsi->fscache = NULL; |
186 | if (!S_ISREG(inode->i_mode)) | ||
197 | return; | 187 | return; |
198 | 188 | nfsi->fscache = fscache_acquire_cookie(NFS_SB(inode->i_sb)->fscache, | |
199 | if ((NFS_SB(sb)->options & NFS_OPTION_FSCACHE)) { | 189 | &nfs_fscache_inode_object_def, |
200 | nfsi->fscache = fscache_acquire_cookie( | 190 | nfsi, false); |
201 | NFS_SB(sb)->fscache, | ||
202 | &nfs_fscache_inode_object_def, | ||
203 | nfsi); | ||
204 | |||
205 | dfprintk(FSCACHE, "NFS: get FH cookie (0x%p/0x%p/0x%p)\n", | ||
206 | sb, nfsi, nfsi->fscache); | ||
207 | } | ||
208 | } | 191 | } |
209 | 192 | ||
210 | /* | 193 | /* |
211 | * Release a per-inode cookie. | 194 | * Release a per-inode cookie. |
212 | */ | 195 | */ |
213 | void nfs_fscache_release_inode_cookie(struct inode *inode) | 196 | void nfs_fscache_clear_inode(struct inode *inode) |
214 | { | 197 | { |
215 | struct nfs_inode *nfsi = NFS_I(inode); | 198 | struct nfs_inode *nfsi = NFS_I(inode); |
199 | struct fscache_cookie *cookie = nfs_i_fscache(inode); | ||
216 | 200 | ||
217 | dfprintk(FSCACHE, "NFS: clear cookie (0x%p/0x%p)\n", | 201 | dfprintk(FSCACHE, "NFS: clear cookie (0x%p/0x%p)\n", nfsi, cookie); |
218 | nfsi, nfsi->fscache); | ||
219 | 202 | ||
220 | fscache_relinquish_cookie(nfsi->fscache, 0); | 203 | fscache_relinquish_cookie(cookie, false); |
221 | nfsi->fscache = NULL; | 204 | nfsi->fscache = NULL; |
222 | } | 205 | } |
223 | 206 | ||
224 | /* | 207 | static bool nfs_fscache_can_enable(void *data) |
225 | * Retire a per-inode cookie, destroying the data attached to it. | ||
226 | */ | ||
227 | void nfs_fscache_zap_inode_cookie(struct inode *inode) | ||
228 | { | 208 | { |
229 | struct nfs_inode *nfsi = NFS_I(inode); | 209 | struct inode *inode = data; |
230 | 210 | ||
231 | dfprintk(FSCACHE, "NFS: zapping cookie (0x%p/0x%p)\n", | 211 | return !inode_is_open_for_write(inode); |
232 | nfsi, nfsi->fscache); | ||
233 | |||
234 | fscache_relinquish_cookie(nfsi->fscache, 1); | ||
235 | nfsi->fscache = NULL; | ||
236 | } | 212 | } |
237 | 213 | ||
238 | /* | 214 | /* |
239 | * Turn off the cache with regard to a per-inode cookie if opened for writing, | 215 | * Enable or disable caching for a file that is being opened as appropriate. |
240 | * invalidating all the pages in the page cache relating to the associated | 216 | * The cookie is allocated when the inode is initialised, but is not enabled at |
241 | * inode to clear the per-page caching. | 217 | * that time. Enablement is deferred to file-open time to avoid stat() and |
242 | */ | 218 | * access() thrashing the cache. |
243 | static void nfs_fscache_disable_inode_cookie(struct inode *inode) | 219 | * |
244 | { | 220 | * For now, with NFS, only regular files that are open read-only will be able |
245 | clear_bit(NFS_INO_FSCACHE, &NFS_I(inode)->flags); | 221 | * to use the cache. |
246 | 222 | * | |
247 | if (NFS_I(inode)->fscache) { | 223 | * We enable the cache for an inode if we open it read-only and it isn't |
248 | dfprintk(FSCACHE, | 224 | * currently open for writing. We disable the cache if the inode is open |
249 | "NFS: nfsi 0x%p turning cache off\n", NFS_I(inode)); | 225 | * write-only. |
250 | 226 | * | |
251 | /* Need to uncache any pages attached to this inode that | 227 | * The caller uses the file struct to pin i_writecount on the inode before |
252 | * fscache knows about before turning off the cache. | 228 | * calling us when a file is opened for writing, so we can make use of that. |
253 | */ | 229 | * |
254 | fscache_uncache_all_inode_pages(NFS_I(inode)->fscache, inode); | 230 | * Note that this may be invoked multiple times in parallel by parallel |
255 | nfs_fscache_zap_inode_cookie(inode); | 231 | * nfs_open() functions. |
256 | } | ||
257 | } | ||
258 | |||
259 | /* | ||
260 | * wait_on_bit() sleep function for uninterruptible waiting | ||
261 | */ | ||
262 | static int nfs_fscache_wait_bit(void *flags) | ||
263 | { | ||
264 | schedule(); | ||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | /* | ||
269 | * Lock against someone else trying to also acquire or relinquish a cookie | ||
270 | */ | ||
271 | static inline void nfs_fscache_inode_lock(struct inode *inode) | ||
272 | { | ||
273 | struct nfs_inode *nfsi = NFS_I(inode); | ||
274 | |||
275 | while (test_and_set_bit(NFS_INO_FSCACHE_LOCK, &nfsi->flags)) | ||
276 | wait_on_bit(&nfsi->flags, NFS_INO_FSCACHE_LOCK, | ||
277 | nfs_fscache_wait_bit, TASK_UNINTERRUPTIBLE); | ||
278 | } | ||
279 | |||
280 | /* | ||
281 | * Unlock cookie management lock | ||
282 | */ | ||
283 | static inline void nfs_fscache_inode_unlock(struct inode *inode) | ||
284 | { | ||
285 | struct nfs_inode *nfsi = NFS_I(inode); | ||
286 | |||
287 | smp_mb__before_clear_bit(); | ||
288 | clear_bit(NFS_INO_FSCACHE_LOCK, &nfsi->flags); | ||
289 | smp_mb__after_clear_bit(); | ||
290 | wake_up_bit(&nfsi->flags, NFS_INO_FSCACHE_LOCK); | ||
291 | } | ||
292 | |||
293 | /* | ||
294 | * Decide if we should enable or disable local caching for this inode. | ||
295 | * - For now, with NFS, only regular files that are open read-only will be able | ||
296 | * to use the cache. | ||
297 | * - May be invoked multiple times in parallel by parallel nfs_open() functions. | ||
298 | */ | ||
299 | void nfs_fscache_set_inode_cookie(struct inode *inode, struct file *filp) | ||
300 | { | ||
301 | if (NFS_FSCACHE(inode)) { | ||
302 | nfs_fscache_inode_lock(inode); | ||
303 | if ((filp->f_flags & O_ACCMODE) != O_RDONLY) | ||
304 | nfs_fscache_disable_inode_cookie(inode); | ||
305 | else | ||
306 | nfs_fscache_enable_inode_cookie(inode); | ||
307 | nfs_fscache_inode_unlock(inode); | ||
308 | } | ||
309 | } | ||
310 | EXPORT_SYMBOL_GPL(nfs_fscache_set_inode_cookie); | ||
311 | |||
312 | /* | ||
313 | * Replace a per-inode cookie due to revalidation detecting a file having | ||
314 | * changed on the server. | ||
315 | */ | 232 | */ |
316 | void nfs_fscache_reset_inode_cookie(struct inode *inode) | 233 | void nfs_fscache_open_file(struct inode *inode, struct file *filp) |
317 | { | 234 | { |
318 | struct nfs_inode *nfsi = NFS_I(inode); | 235 | struct nfs_inode *nfsi = NFS_I(inode); |
319 | struct nfs_server *nfss = NFS_SERVER(inode); | 236 | struct fscache_cookie *cookie = nfs_i_fscache(inode); |
320 | NFS_IFDEBUG(struct fscache_cookie *old = nfsi->fscache); | ||
321 | 237 | ||
322 | nfs_fscache_inode_lock(inode); | 238 | if (!fscache_cookie_valid(cookie)) |
323 | if (nfsi->fscache) { | 239 | return; |
324 | /* retire the current fscache cache and get a new one */ | ||
325 | fscache_relinquish_cookie(nfsi->fscache, 1); | ||
326 | |||
327 | nfsi->fscache = fscache_acquire_cookie( | ||
328 | nfss->nfs_client->fscache, | ||
329 | &nfs_fscache_inode_object_def, | ||
330 | nfsi); | ||
331 | 240 | ||
332 | dfprintk(FSCACHE, | 241 | if (inode_is_open_for_write(inode)) { |
333 | "NFS: revalidation new cookie (0x%p/0x%p/0x%p/0x%p)\n", | 242 | dfprintk(FSCACHE, "NFS: nfsi 0x%p disabling cache\n", nfsi); |
334 | nfss, nfsi, old, nfsi->fscache); | 243 | clear_bit(NFS_INO_FSCACHE, &nfsi->flags); |
244 | fscache_disable_cookie(cookie, true); | ||
245 | fscache_uncache_all_inode_pages(cookie, inode); | ||
246 | } else { | ||
247 | dfprintk(FSCACHE, "NFS: nfsi 0x%p enabling cache\n", nfsi); | ||
248 | fscache_enable_cookie(cookie, nfs_fscache_can_enable, inode); | ||
249 | if (fscache_cookie_enabled(cookie)) | ||
250 | set_bit(NFS_INO_FSCACHE, &NFS_I(inode)->flags); | ||
335 | } | 251 | } |
336 | nfs_fscache_inode_unlock(inode); | ||
337 | } | 252 | } |
253 | EXPORT_SYMBOL_GPL(nfs_fscache_open_file); | ||
338 | 254 | ||
339 | /* | 255 | /* |
340 | * Release the caching state associated with a page, if the page isn't busy | 256 | * Release the caching state associated with a page, if the page isn't busy |
@@ -344,12 +260,11 @@ void nfs_fscache_reset_inode_cookie(struct inode *inode) | |||
344 | int nfs_fscache_release_page(struct page *page, gfp_t gfp) | 260 | int nfs_fscache_release_page(struct page *page, gfp_t gfp) |
345 | { | 261 | { |
346 | if (PageFsCache(page)) { | 262 | if (PageFsCache(page)) { |
347 | struct nfs_inode *nfsi = NFS_I(page->mapping->host); | 263 | struct fscache_cookie *cookie = nfs_i_fscache(page->mapping->host); |
348 | struct fscache_cookie *cookie = nfsi->fscache; | ||
349 | 264 | ||
350 | BUG_ON(!cookie); | 265 | BUG_ON(!cookie); |
351 | dfprintk(FSCACHE, "NFS: fscache releasepage (0x%p/0x%p/0x%p)\n", | 266 | dfprintk(FSCACHE, "NFS: fscache releasepage (0x%p/0x%p/0x%p)\n", |
352 | cookie, page, nfsi); | 267 | cookie, page, NFS_I(page->mapping->host)); |
353 | 268 | ||
354 | if (!fscache_maybe_release_page(cookie, page, gfp)) | 269 | if (!fscache_maybe_release_page(cookie, page, gfp)) |
355 | return 0; | 270 | return 0; |
@@ -367,13 +282,12 @@ int nfs_fscache_release_page(struct page *page, gfp_t gfp) | |||
367 | */ | 282 | */ |
368 | void __nfs_fscache_invalidate_page(struct page *page, struct inode *inode) | 283 | void __nfs_fscache_invalidate_page(struct page *page, struct inode *inode) |
369 | { | 284 | { |
370 | struct nfs_inode *nfsi = NFS_I(inode); | 285 | struct fscache_cookie *cookie = nfs_i_fscache(inode); |
371 | struct fscache_cookie *cookie = nfsi->fscache; | ||
372 | 286 | ||
373 | BUG_ON(!cookie); | 287 | BUG_ON(!cookie); |
374 | 288 | ||
375 | dfprintk(FSCACHE, "NFS: fscache invalidatepage (0x%p/0x%p/0x%p)\n", | 289 | dfprintk(FSCACHE, "NFS: fscache invalidatepage (0x%p/0x%p/0x%p)\n", |
376 | cookie, page, nfsi); | 290 | cookie, page, NFS_I(inode)); |
377 | 291 | ||
378 | fscache_wait_on_page_write(cookie, page); | 292 | fscache_wait_on_page_write(cookie, page); |
379 | 293 | ||
@@ -417,9 +331,9 @@ int __nfs_readpage_from_fscache(struct nfs_open_context *ctx, | |||
417 | 331 | ||
418 | dfprintk(FSCACHE, | 332 | dfprintk(FSCACHE, |
419 | "NFS: readpage_from_fscache(fsc:%p/p:%p(i:%lx f:%lx)/0x%p)\n", | 333 | "NFS: readpage_from_fscache(fsc:%p/p:%p(i:%lx f:%lx)/0x%p)\n", |
420 | NFS_I(inode)->fscache, page, page->index, page->flags, inode); | 334 | nfs_i_fscache(inode), page, page->index, page->flags, inode); |
421 | 335 | ||
422 | ret = fscache_read_or_alloc_page(NFS_I(inode)->fscache, | 336 | ret = fscache_read_or_alloc_page(nfs_i_fscache(inode), |
423 | page, | 337 | page, |
424 | nfs_readpage_from_fscache_complete, | 338 | nfs_readpage_from_fscache_complete, |
425 | ctx, | 339 | ctx, |
@@ -459,9 +373,9 @@ int __nfs_readpages_from_fscache(struct nfs_open_context *ctx, | |||
459 | int ret; | 373 | int ret; |
460 | 374 | ||
461 | dfprintk(FSCACHE, "NFS: nfs_getpages_from_fscache (0x%p/%u/0x%p)\n", | 375 | dfprintk(FSCACHE, "NFS: nfs_getpages_from_fscache (0x%p/%u/0x%p)\n", |
462 | NFS_I(inode)->fscache, npages, inode); | 376 | nfs_i_fscache(inode), npages, inode); |
463 | 377 | ||
464 | ret = fscache_read_or_alloc_pages(NFS_I(inode)->fscache, | 378 | ret = fscache_read_or_alloc_pages(nfs_i_fscache(inode), |
465 | mapping, pages, nr_pages, | 379 | mapping, pages, nr_pages, |
466 | nfs_readpage_from_fscache_complete, | 380 | nfs_readpage_from_fscache_complete, |
467 | ctx, | 381 | ctx, |
@@ -506,15 +420,15 @@ void __nfs_readpage_to_fscache(struct inode *inode, struct page *page, int sync) | |||
506 | 420 | ||
507 | dfprintk(FSCACHE, | 421 | dfprintk(FSCACHE, |
508 | "NFS: readpage_to_fscache(fsc:%p/p:%p(i:%lx f:%lx)/%d)\n", | 422 | "NFS: readpage_to_fscache(fsc:%p/p:%p(i:%lx f:%lx)/%d)\n", |
509 | NFS_I(inode)->fscache, page, page->index, page->flags, sync); | 423 | nfs_i_fscache(inode), page, page->index, page->flags, sync); |
510 | 424 | ||
511 | ret = fscache_write_page(NFS_I(inode)->fscache, page, GFP_KERNEL); | 425 | ret = fscache_write_page(nfs_i_fscache(inode), page, GFP_KERNEL); |
512 | dfprintk(FSCACHE, | 426 | dfprintk(FSCACHE, |
513 | "NFS: readpage_to_fscache: p:%p(i:%lu f:%lx) ret %d\n", | 427 | "NFS: readpage_to_fscache: p:%p(i:%lu f:%lx) ret %d\n", |
514 | page, page->index, page->flags, ret); | 428 | page, page->index, page->flags, ret); |
515 | 429 | ||
516 | if (ret != 0) { | 430 | if (ret != 0) { |
517 | fscache_uncache_page(NFS_I(inode)->fscache, page); | 431 | fscache_uncache_page(nfs_i_fscache(inode), page); |
518 | nfs_add_fscache_stats(inode, | 432 | nfs_add_fscache_stats(inode, |
519 | NFSIOS_FSCACHE_PAGES_WRITTEN_FAIL, 1); | 433 | NFSIOS_FSCACHE_PAGES_WRITTEN_FAIL, 1); |
520 | nfs_add_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_UNCACHED, 1); | 434 | nfs_add_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_UNCACHED, 1); |
diff --git a/fs/nfs/fscache.h b/fs/nfs/fscache.h index 4ecb76652eba..d7fe3e799f2f 100644 --- a/fs/nfs/fscache.h +++ b/fs/nfs/fscache.h | |||
@@ -76,11 +76,9 @@ extern void nfs_fscache_release_client_cookie(struct nfs_client *); | |||
76 | extern void nfs_fscache_get_super_cookie(struct super_block *, const char *, int); | 76 | extern void nfs_fscache_get_super_cookie(struct super_block *, const char *, int); |
77 | extern void nfs_fscache_release_super_cookie(struct super_block *); | 77 | extern void nfs_fscache_release_super_cookie(struct super_block *); |
78 | 78 | ||
79 | extern void nfs_fscache_init_inode_cookie(struct inode *); | 79 | extern void nfs_fscache_init_inode(struct inode *); |
80 | extern void nfs_fscache_release_inode_cookie(struct inode *); | 80 | extern void nfs_fscache_clear_inode(struct inode *); |
81 | extern void nfs_fscache_zap_inode_cookie(struct inode *); | 81 | extern void nfs_fscache_open_file(struct inode *, struct file *); |
82 | extern void nfs_fscache_set_inode_cookie(struct inode *, struct file *); | ||
83 | extern void nfs_fscache_reset_inode_cookie(struct inode *); | ||
84 | 82 | ||
85 | extern void __nfs_fscache_invalidate_page(struct page *, struct inode *); | 83 | extern void __nfs_fscache_invalidate_page(struct page *, struct inode *); |
86 | extern int nfs_fscache_release_page(struct page *, gfp_t); | 84 | extern int nfs_fscache_release_page(struct page *, gfp_t); |
@@ -187,12 +185,10 @@ static inline void nfs_fscache_release_client_cookie(struct nfs_client *clp) {} | |||
187 | 185 | ||
188 | static inline void nfs_fscache_release_super_cookie(struct super_block *sb) {} | 186 | static inline void nfs_fscache_release_super_cookie(struct super_block *sb) {} |
189 | 187 | ||
190 | static inline void nfs_fscache_init_inode_cookie(struct inode *inode) {} | 188 | static inline void nfs_fscache_init_inode(struct inode *inode) {} |
191 | static inline void nfs_fscache_release_inode_cookie(struct inode *inode) {} | 189 | static inline void nfs_fscache_clear_inode(struct inode *inode) {} |
192 | static inline void nfs_fscache_zap_inode_cookie(struct inode *inode) {} | 190 | static inline void nfs_fscache_open_file(struct inode *inode, |
193 | static inline void nfs_fscache_set_inode_cookie(struct inode *inode, | 191 | struct file *filp) {} |
194 | struct file *filp) {} | ||
195 | static inline void nfs_fscache_reset_inode_cookie(struct inode *inode) {} | ||
196 | 192 | ||
197 | static inline int nfs_fscache_release_page(struct page *page, gfp_t gfp) | 193 | static inline int nfs_fscache_release_page(struct page *page, gfp_t gfp) |
198 | { | 194 | { |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index eda8879171c4..18ab2da4eeb6 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -122,7 +122,7 @@ void nfs_clear_inode(struct inode *inode) | |||
122 | WARN_ON_ONCE(!list_empty(&NFS_I(inode)->open_files)); | 122 | WARN_ON_ONCE(!list_empty(&NFS_I(inode)->open_files)); |
123 | nfs_zap_acl_cache(inode); | 123 | nfs_zap_acl_cache(inode); |
124 | nfs_access_zap_cache(inode); | 124 | nfs_access_zap_cache(inode); |
125 | nfs_fscache_release_inode_cookie(inode); | 125 | nfs_fscache_clear_inode(inode); |
126 | } | 126 | } |
127 | EXPORT_SYMBOL_GPL(nfs_clear_inode); | 127 | EXPORT_SYMBOL_GPL(nfs_clear_inode); |
128 | 128 | ||
@@ -274,12 +274,6 @@ void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr, | |||
274 | if (label == NULL) | 274 | if (label == NULL) |
275 | return; | 275 | return; |
276 | 276 | ||
277 | if (nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL) == 0) | ||
278 | return; | ||
279 | |||
280 | if (NFS_SERVER(inode)->nfs_client->cl_minorversion < 2) | ||
281 | return; | ||
282 | |||
283 | if ((fattr->valid & NFS_ATTR_FATTR_V4_SECURITY_LABEL) && inode->i_security) { | 277 | if ((fattr->valid & NFS_ATTR_FATTR_V4_SECURITY_LABEL) && inode->i_security) { |
284 | error = security_inode_notifysecctx(inode, label->label, | 278 | error = security_inode_notifysecctx(inode, label->label, |
285 | label->len); | 279 | label->len); |
@@ -459,7 +453,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st | |||
459 | nfsi->attrtimeo_timestamp = now; | 453 | nfsi->attrtimeo_timestamp = now; |
460 | nfsi->access_cache = RB_ROOT; | 454 | nfsi->access_cache = RB_ROOT; |
461 | 455 | ||
462 | nfs_fscache_init_inode_cookie(inode); | 456 | nfs_fscache_init_inode(inode); |
463 | 457 | ||
464 | unlock_new_inode(inode); | 458 | unlock_new_inode(inode); |
465 | } else | 459 | } else |
@@ -854,7 +848,7 @@ int nfs_open(struct inode *inode, struct file *filp) | |||
854 | return PTR_ERR(ctx); | 848 | return PTR_ERR(ctx); |
855 | nfs_file_set_open_context(filp, ctx); | 849 | nfs_file_set_open_context(filp, ctx); |
856 | put_nfs_open_context(ctx); | 850 | put_nfs_open_context(ctx); |
857 | nfs_fscache_set_inode_cookie(inode, filp); | 851 | nfs_fscache_open_file(inode, filp); |
858 | return 0; | 852 | return 0; |
859 | } | 853 | } |
860 | 854 | ||
@@ -923,6 +917,8 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
923 | if (nfsi->cache_validity & NFS_INO_INVALID_ACL) | 917 | if (nfsi->cache_validity & NFS_INO_INVALID_ACL) |
924 | nfs_zap_acl_cache(inode); | 918 | nfs_zap_acl_cache(inode); |
925 | 919 | ||
920 | nfs_setsecurity(inode, fattr, label); | ||
921 | |||
926 | dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n", | 922 | dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n", |
927 | inode->i_sb->s_id, | 923 | inode->i_sb->s_id, |
928 | (long long)NFS_FILEID(inode)); | 924 | (long long)NFS_FILEID(inode)); |
@@ -1209,6 +1205,7 @@ u32 _nfs_display_fhandle_hash(const struct nfs_fh *fh) | |||
1209 | * not on the result */ | 1205 | * not on the result */ |
1210 | return nfs_fhandle_hash(fh); | 1206 | return nfs_fhandle_hash(fh); |
1211 | } | 1207 | } |
1208 | EXPORT_SYMBOL_GPL(_nfs_display_fhandle_hash); | ||
1212 | 1209 | ||
1213 | /* | 1210 | /* |
1214 | * _nfs_display_fhandle - display an NFS file handle on the console | 1211 | * _nfs_display_fhandle - display an NFS file handle on the console |
@@ -1253,6 +1250,7 @@ void _nfs_display_fhandle(const struct nfs_fh *fh, const char *caption) | |||
1253 | } | 1250 | } |
1254 | } | 1251 | } |
1255 | } | 1252 | } |
1253 | EXPORT_SYMBOL_GPL(_nfs_display_fhandle); | ||
1256 | #endif | 1254 | #endif |
1257 | 1255 | ||
1258 | /** | 1256 | /** |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 38da8c2b81ac..bca6a3e3c49c 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -88,8 +88,8 @@ struct nfs_parsed_mount_data { | |||
88 | unsigned int namlen; | 88 | unsigned int namlen; |
89 | unsigned int options; | 89 | unsigned int options; |
90 | unsigned int bsize; | 90 | unsigned int bsize; |
91 | unsigned int auth_flavor_len; | 91 | struct nfs_auth_info auth_info; |
92 | rpc_authflavor_t auth_flavors[1]; | 92 | rpc_authflavor_t selected_flavor; |
93 | char *client_address; | 93 | char *client_address; |
94 | unsigned int version; | 94 | unsigned int version; |
95 | unsigned int minorversion; | 95 | unsigned int minorversion; |
@@ -154,6 +154,7 @@ struct nfs_client *nfs_get_client(const struct nfs_client_initdata *, | |||
154 | rpc_authflavor_t); | 154 | rpc_authflavor_t); |
155 | int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *, struct nfs_fattr *); | 155 | int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *, struct nfs_fattr *); |
156 | void nfs_server_insert_lists(struct nfs_server *); | 156 | void nfs_server_insert_lists(struct nfs_server *); |
157 | void nfs_server_remove_lists(struct nfs_server *); | ||
157 | void nfs_init_timeout_values(struct rpc_timeout *, int, unsigned int, unsigned int); | 158 | void nfs_init_timeout_values(struct rpc_timeout *, int, unsigned int, unsigned int); |
158 | int nfs_init_server_rpcclient(struct nfs_server *, const struct rpc_timeout *t, | 159 | int nfs_init_server_rpcclient(struct nfs_server *, const struct rpc_timeout *t, |
159 | rpc_authflavor_t); | 160 | rpc_authflavor_t); |
@@ -174,6 +175,8 @@ extern struct nfs_server *nfs4_create_server( | |||
174 | struct nfs_subversion *); | 175 | struct nfs_subversion *); |
175 | extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *, | 176 | extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *, |
176 | struct nfs_fh *); | 177 | struct nfs_fh *); |
178 | extern int nfs4_update_server(struct nfs_server *server, const char *hostname, | ||
179 | struct sockaddr *sap, size_t salen); | ||
177 | extern void nfs_free_server(struct nfs_server *server); | 180 | extern void nfs_free_server(struct nfs_server *server); |
178 | extern struct nfs_server *nfs_clone_server(struct nfs_server *, | 181 | extern struct nfs_server *nfs_clone_server(struct nfs_server *, |
179 | struct nfs_fh *, | 182 | struct nfs_fh *, |
@@ -323,6 +326,7 @@ extern struct file_system_type nfs_xdev_fs_type; | |||
323 | extern struct file_system_type nfs4_xdev_fs_type; | 326 | extern struct file_system_type nfs4_xdev_fs_type; |
324 | extern struct file_system_type nfs4_referral_fs_type; | 327 | extern struct file_system_type nfs4_referral_fs_type; |
325 | #endif | 328 | #endif |
329 | bool nfs_auth_info_match(const struct nfs_auth_info *, rpc_authflavor_t); | ||
326 | struct dentry *nfs_try_mount(int, const char *, struct nfs_mount_info *, | 330 | struct dentry *nfs_try_mount(int, const char *, struct nfs_mount_info *, |
327 | struct nfs_subversion *); | 331 | struct nfs_subversion *); |
328 | void nfs_initialise_sb(struct super_block *); | 332 | void nfs_initialise_sb(struct super_block *); |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 28842abafab4..3ce79b04522e 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -29,6 +29,8 @@ enum nfs4_client_state { | |||
29 | NFS4CLNT_SERVER_SCOPE_MISMATCH, | 29 | NFS4CLNT_SERVER_SCOPE_MISMATCH, |
30 | NFS4CLNT_PURGE_STATE, | 30 | NFS4CLNT_PURGE_STATE, |
31 | NFS4CLNT_BIND_CONN_TO_SESSION, | 31 | NFS4CLNT_BIND_CONN_TO_SESSION, |
32 | NFS4CLNT_MOVED, | ||
33 | NFS4CLNT_LEASE_MOVED, | ||
32 | }; | 34 | }; |
33 | 35 | ||
34 | #define NFS4_RENEW_TIMEOUT 0x01 | 36 | #define NFS4_RENEW_TIMEOUT 0x01 |
@@ -50,6 +52,7 @@ struct nfs4_minor_version_ops { | |||
50 | const struct nfs4_state_recovery_ops *reboot_recovery_ops; | 52 | const struct nfs4_state_recovery_ops *reboot_recovery_ops; |
51 | const struct nfs4_state_recovery_ops *nograce_recovery_ops; | 53 | const struct nfs4_state_recovery_ops *nograce_recovery_ops; |
52 | const struct nfs4_state_maintenance_ops *state_renewal_ops; | 54 | const struct nfs4_state_maintenance_ops *state_renewal_ops; |
55 | const struct nfs4_mig_recovery_ops *mig_recovery_ops; | ||
53 | }; | 56 | }; |
54 | 57 | ||
55 | #define NFS_SEQID_CONFIRMED 1 | 58 | #define NFS_SEQID_CONFIRMED 1 |
@@ -203,6 +206,12 @@ struct nfs4_state_maintenance_ops { | |||
203 | int (*renew_lease)(struct nfs_client *, struct rpc_cred *); | 206 | int (*renew_lease)(struct nfs_client *, struct rpc_cred *); |
204 | }; | 207 | }; |
205 | 208 | ||
209 | struct nfs4_mig_recovery_ops { | ||
210 | int (*get_locations)(struct inode *, struct nfs4_fs_locations *, | ||
211 | struct page *, struct rpc_cred *); | ||
212 | int (*fsid_present)(struct inode *, struct rpc_cred *); | ||
213 | }; | ||
214 | |||
206 | extern const struct dentry_operations nfs4_dentry_operations; | 215 | extern const struct dentry_operations nfs4_dentry_operations; |
207 | 216 | ||
208 | /* dir.c */ | 217 | /* dir.c */ |
@@ -213,10 +222,11 @@ int nfs_atomic_open(struct inode *, struct dentry *, struct file *, | |||
213 | extern struct file_system_type nfs4_fs_type; | 222 | extern struct file_system_type nfs4_fs_type; |
214 | 223 | ||
215 | /* nfs4namespace.c */ | 224 | /* nfs4namespace.c */ |
216 | rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *); | ||
217 | struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *, struct inode *, struct qstr *); | 225 | struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *, struct inode *, struct qstr *); |
218 | struct vfsmount *nfs4_submount(struct nfs_server *, struct dentry *, | 226 | struct vfsmount *nfs4_submount(struct nfs_server *, struct dentry *, |
219 | struct nfs_fh *, struct nfs_fattr *); | 227 | struct nfs_fh *, struct nfs_fattr *); |
228 | int nfs4_replace_transport(struct nfs_server *server, | ||
229 | const struct nfs4_fs_locations *locations); | ||
220 | 230 | ||
221 | /* nfs4proc.c */ | 231 | /* nfs4proc.c */ |
222 | extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *, struct nfs4_setclientid_res *); | 232 | extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *, struct nfs4_setclientid_res *); |
@@ -231,6 +241,9 @@ extern int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait); | |||
231 | extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); | 241 | extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); |
232 | extern int nfs4_proc_fs_locations(struct rpc_clnt *, struct inode *, const struct qstr *, | 242 | extern int nfs4_proc_fs_locations(struct rpc_clnt *, struct inode *, const struct qstr *, |
233 | struct nfs4_fs_locations *, struct page *); | 243 | struct nfs4_fs_locations *, struct page *); |
244 | extern int nfs4_proc_get_locations(struct inode *, struct nfs4_fs_locations *, | ||
245 | struct page *page, struct rpc_cred *); | ||
246 | extern int nfs4_proc_fsid_present(struct inode *, struct rpc_cred *); | ||
234 | extern struct rpc_clnt *nfs4_proc_lookup_mountpoint(struct inode *, struct qstr *, | 247 | extern struct rpc_clnt *nfs4_proc_lookup_mountpoint(struct inode *, struct qstr *, |
235 | struct nfs_fh *, struct nfs_fattr *); | 248 | struct nfs_fh *, struct nfs_fattr *); |
236 | extern int nfs4_proc_secinfo(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *); | 249 | extern int nfs4_proc_secinfo(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *); |
@@ -411,6 +424,8 @@ extern int nfs4_client_recover_expired_lease(struct nfs_client *clp); | |||
411 | extern void nfs4_schedule_state_manager(struct nfs_client *); | 424 | extern void nfs4_schedule_state_manager(struct nfs_client *); |
412 | extern void nfs4_schedule_path_down_recovery(struct nfs_client *clp); | 425 | extern void nfs4_schedule_path_down_recovery(struct nfs_client *clp); |
413 | extern int nfs4_schedule_stateid_recovery(const struct nfs_server *, struct nfs4_state *); | 426 | extern int nfs4_schedule_stateid_recovery(const struct nfs_server *, struct nfs4_state *); |
427 | extern int nfs4_schedule_migration_recovery(const struct nfs_server *); | ||
428 | extern void nfs4_schedule_lease_moved_recovery(struct nfs_client *); | ||
414 | extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags); | 429 | extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags); |
415 | extern void nfs41_handle_server_scope(struct nfs_client *, | 430 | extern void nfs41_handle_server_scope(struct nfs_client *, |
416 | struct nfs41_server_scope **); | 431 | struct nfs41_server_scope **); |
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index a860ab566d6e..b4a160a405ce 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c | |||
@@ -197,6 +197,7 @@ struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init) | |||
197 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; | 197 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; |
198 | clp->cl_minorversion = cl_init->minorversion; | 198 | clp->cl_minorversion = cl_init->minorversion; |
199 | clp->cl_mvops = nfs_v4_minor_ops[cl_init->minorversion]; | 199 | clp->cl_mvops = nfs_v4_minor_ops[cl_init->minorversion]; |
200 | clp->cl_mig_gen = 1; | ||
200 | return clp; | 201 | return clp; |
201 | 202 | ||
202 | error: | 203 | error: |
@@ -368,6 +369,7 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp, | |||
368 | if (clp->cl_minorversion != 0) | 369 | if (clp->cl_minorversion != 0) |
369 | __set_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags); | 370 | __set_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags); |
370 | __set_bit(NFS_CS_DISCRTRY, &clp->cl_flags); | 371 | __set_bit(NFS_CS_DISCRTRY, &clp->cl_flags); |
372 | __set_bit(NFS_CS_NO_RETRANS_TIMEOUT, &clp->cl_flags); | ||
371 | error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_GSS_KRB5I); | 373 | error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_GSS_KRB5I); |
372 | if (error == -EINVAL) | 374 | if (error == -EINVAL) |
373 | error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX); | 375 | error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX); |
@@ -924,7 +926,7 @@ static int nfs4_server_common_setup(struct nfs_server *server, | |||
924 | dprintk("Server FSID: %llx:%llx\n", | 926 | dprintk("Server FSID: %llx:%llx\n", |
925 | (unsigned long long) server->fsid.major, | 927 | (unsigned long long) server->fsid.major, |
926 | (unsigned long long) server->fsid.minor); | 928 | (unsigned long long) server->fsid.minor); |
927 | dprintk("Mount FH: %d\n", mntfh->size); | 929 | nfs_display_fhandle(mntfh, "Pseudo-fs root FH"); |
928 | 930 | ||
929 | nfs4_session_set_rwsize(server); | 931 | nfs4_session_set_rwsize(server); |
930 | 932 | ||
@@ -947,9 +949,8 @@ out: | |||
947 | * Create a version 4 volume record | 949 | * Create a version 4 volume record |
948 | */ | 950 | */ |
949 | static int nfs4_init_server(struct nfs_server *server, | 951 | static int nfs4_init_server(struct nfs_server *server, |
950 | const struct nfs_parsed_mount_data *data) | 952 | struct nfs_parsed_mount_data *data) |
951 | { | 953 | { |
952 | rpc_authflavor_t pseudoflavor = RPC_AUTH_UNIX; | ||
953 | struct rpc_timeout timeparms; | 954 | struct rpc_timeout timeparms; |
954 | int error; | 955 | int error; |
955 | 956 | ||
@@ -961,9 +962,15 @@ static int nfs4_init_server(struct nfs_server *server, | |||
961 | /* Initialise the client representation from the mount data */ | 962 | /* Initialise the client representation from the mount data */ |
962 | server->flags = data->flags; | 963 | server->flags = data->flags; |
963 | server->options = data->options; | 964 | server->options = data->options; |
965 | server->auth_info = data->auth_info; | ||
964 | 966 | ||
965 | if (data->auth_flavor_len >= 1) | 967 | /* Use the first specified auth flavor. If this flavor isn't |
966 | pseudoflavor = data->auth_flavors[0]; | 968 | * allowed by the server, use the SECINFO path to try the |
969 | * other specified flavors */ | ||
970 | if (data->auth_info.flavor_len >= 1) | ||
971 | data->selected_flavor = data->auth_info.flavors[0]; | ||
972 | else | ||
973 | data->selected_flavor = RPC_AUTH_UNIX; | ||
967 | 974 | ||
968 | /* Get a client record */ | 975 | /* Get a client record */ |
969 | error = nfs4_set_client(server, | 976 | error = nfs4_set_client(server, |
@@ -971,7 +978,7 @@ static int nfs4_init_server(struct nfs_server *server, | |||
971 | (const struct sockaddr *)&data->nfs_server.address, | 978 | (const struct sockaddr *)&data->nfs_server.address, |
972 | data->nfs_server.addrlen, | 979 | data->nfs_server.addrlen, |
973 | data->client_address, | 980 | data->client_address, |
974 | pseudoflavor, | 981 | data->selected_flavor, |
975 | data->nfs_server.protocol, | 982 | data->nfs_server.protocol, |
976 | &timeparms, | 983 | &timeparms, |
977 | data->minorversion, | 984 | data->minorversion, |
@@ -991,7 +998,8 @@ static int nfs4_init_server(struct nfs_server *server, | |||
991 | 998 | ||
992 | server->port = data->nfs_server.port; | 999 | server->port = data->nfs_server.port; |
993 | 1000 | ||
994 | error = nfs_init_server_rpcclient(server, &timeparms, pseudoflavor); | 1001 | error = nfs_init_server_rpcclient(server, &timeparms, |
1002 | data->selected_flavor); | ||
995 | 1003 | ||
996 | error: | 1004 | error: |
997 | /* Done */ | 1005 | /* Done */ |
@@ -1018,7 +1026,7 @@ struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info, | |||
1018 | if (!server) | 1026 | if (!server) |
1019 | return ERR_PTR(-ENOMEM); | 1027 | return ERR_PTR(-ENOMEM); |
1020 | 1028 | ||
1021 | auth_probe = mount_info->parsed->auth_flavor_len < 1; | 1029 | auth_probe = mount_info->parsed->auth_info.flavor_len < 1; |
1022 | 1030 | ||
1023 | /* set up the general RPC client */ | 1031 | /* set up the general RPC client */ |
1024 | error = nfs4_init_server(server, mount_info->parsed); | 1032 | error = nfs4_init_server(server, mount_info->parsed); |
@@ -1046,6 +1054,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
1046 | { | 1054 | { |
1047 | struct nfs_client *parent_client; | 1055 | struct nfs_client *parent_client; |
1048 | struct nfs_server *server, *parent_server; | 1056 | struct nfs_server *server, *parent_server; |
1057 | bool auth_probe; | ||
1049 | int error; | 1058 | int error; |
1050 | 1059 | ||
1051 | dprintk("--> nfs4_create_referral_server()\n"); | 1060 | dprintk("--> nfs4_create_referral_server()\n"); |
@@ -1078,8 +1087,9 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
1078 | if (error < 0) | 1087 | if (error < 0) |
1079 | goto error; | 1088 | goto error; |
1080 | 1089 | ||
1081 | error = nfs4_server_common_setup(server, mntfh, | 1090 | auth_probe = parent_server->auth_info.flavor_len < 1; |
1082 | !(parent_server->flags & NFS_MOUNT_SECFLAVOUR)); | 1091 | |
1092 | error = nfs4_server_common_setup(server, mntfh, auth_probe); | ||
1083 | if (error < 0) | 1093 | if (error < 0) |
1084 | goto error; | 1094 | goto error; |
1085 | 1095 | ||
@@ -1091,3 +1101,111 @@ error: | |||
1091 | dprintk("<-- nfs4_create_referral_server() = error %d\n", error); | 1101 | dprintk("<-- nfs4_create_referral_server() = error %d\n", error); |
1092 | return ERR_PTR(error); | 1102 | return ERR_PTR(error); |
1093 | } | 1103 | } |
1104 | |||
1105 | /* | ||
1106 | * Grab the destination's particulars, including lease expiry time. | ||
1107 | * | ||
1108 | * Returns zero if probe succeeded and retrieved FSID matches the FSID | ||
1109 | * we have cached. | ||
1110 | */ | ||
1111 | static int nfs_probe_destination(struct nfs_server *server) | ||
1112 | { | ||
1113 | struct inode *inode = server->super->s_root->d_inode; | ||
1114 | struct nfs_fattr *fattr; | ||
1115 | int error; | ||
1116 | |||
1117 | fattr = nfs_alloc_fattr(); | ||
1118 | if (fattr == NULL) | ||
1119 | return -ENOMEM; | ||
1120 | |||
1121 | /* Sanity: the probe won't work if the destination server | ||
1122 | * does not recognize the migrated FH. */ | ||
1123 | error = nfs_probe_fsinfo(server, NFS_FH(inode), fattr); | ||
1124 | |||
1125 | nfs_free_fattr(fattr); | ||
1126 | return error; | ||
1127 | } | ||
1128 | |||
1129 | /** | ||
1130 | * nfs4_update_server - Move an nfs_server to a different nfs_client | ||
1131 | * | ||
1132 | * @server: represents FSID to be moved | ||
1133 | * @hostname: new end-point's hostname | ||
1134 | * @sap: new end-point's socket address | ||
1135 | * @salen: size of "sap" | ||
1136 | * | ||
1137 | * The nfs_server must be quiescent before this function is invoked. | ||
1138 | * Either its session is drained (NFSv4.1+), or its transport is | ||
1139 | * plugged and drained (NFSv4.0). | ||
1140 | * | ||
1141 | * Returns zero on success, or a negative errno value. | ||
1142 | */ | ||
1143 | int nfs4_update_server(struct nfs_server *server, const char *hostname, | ||
1144 | struct sockaddr *sap, size_t salen) | ||
1145 | { | ||
1146 | struct nfs_client *clp = server->nfs_client; | ||
1147 | struct rpc_clnt *clnt = server->client; | ||
1148 | struct xprt_create xargs = { | ||
1149 | .ident = clp->cl_proto, | ||
1150 | .net = &init_net, | ||
1151 | .dstaddr = sap, | ||
1152 | .addrlen = salen, | ||
1153 | .servername = hostname, | ||
1154 | }; | ||
1155 | char buf[INET6_ADDRSTRLEN + 1]; | ||
1156 | struct sockaddr_storage address; | ||
1157 | struct sockaddr *localaddr = (struct sockaddr *)&address; | ||
1158 | int error; | ||
1159 | |||
1160 | dprintk("--> %s: move FSID %llx:%llx to \"%s\")\n", __func__, | ||
1161 | (unsigned long long)server->fsid.major, | ||
1162 | (unsigned long long)server->fsid.minor, | ||
1163 | hostname); | ||
1164 | |||
1165 | error = rpc_switch_client_transport(clnt, &xargs, clnt->cl_timeout); | ||
1166 | if (error != 0) { | ||
1167 | dprintk("<-- %s(): rpc_switch_client_transport returned %d\n", | ||
1168 | __func__, error); | ||
1169 | goto out; | ||
1170 | } | ||
1171 | |||
1172 | error = rpc_localaddr(clnt, localaddr, sizeof(address)); | ||
1173 | if (error != 0) { | ||
1174 | dprintk("<-- %s(): rpc_localaddr returned %d\n", | ||
1175 | __func__, error); | ||
1176 | goto out; | ||
1177 | } | ||
1178 | |||
1179 | error = -EAFNOSUPPORT; | ||
1180 | if (rpc_ntop(localaddr, buf, sizeof(buf)) == 0) { | ||
1181 | dprintk("<-- %s(): rpc_ntop returned %d\n", | ||
1182 | __func__, error); | ||
1183 | goto out; | ||
1184 | } | ||
1185 | |||
1186 | nfs_server_remove_lists(server); | ||
1187 | error = nfs4_set_client(server, hostname, sap, salen, buf, | ||
1188 | clp->cl_rpcclient->cl_auth->au_flavor, | ||
1189 | clp->cl_proto, clnt->cl_timeout, | ||
1190 | clp->cl_minorversion, clp->cl_net); | ||
1191 | nfs_put_client(clp); | ||
1192 | if (error != 0) { | ||
1193 | nfs_server_insert_lists(server); | ||
1194 | dprintk("<-- %s(): nfs4_set_client returned %d\n", | ||
1195 | __func__, error); | ||
1196 | goto out; | ||
1197 | } | ||
1198 | |||
1199 | if (server->nfs_client->cl_hostname == NULL) | ||
1200 | server->nfs_client->cl_hostname = kstrdup(hostname, GFP_KERNEL); | ||
1201 | nfs_server_insert_lists(server); | ||
1202 | |||
1203 | error = nfs_probe_destination(server); | ||
1204 | if (error < 0) | ||
1205 | goto out; | ||
1206 | |||
1207 | dprintk("<-- %s() succeeded\n", __func__); | ||
1208 | |||
1209 | out: | ||
1210 | return error; | ||
1211 | } | ||
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index 77efaf15ec90..1f01b55692ee 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c | |||
@@ -75,7 +75,7 @@ nfs4_file_open(struct inode *inode, struct file *filp) | |||
75 | 75 | ||
76 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | 76 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
77 | nfs_file_set_open_context(filp, ctx); | 77 | nfs_file_set_open_context(filp, ctx); |
78 | nfs_fscache_set_inode_cookie(inode, filp); | 78 | nfs_fscache_open_file(inode, filp); |
79 | err = 0; | 79 | err = 0; |
80 | 80 | ||
81 | out_put_ctx: | 81 | out_put_ctx: |
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index 2288cd3c9278..c08cbf40c59e 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c | |||
@@ -137,6 +137,7 @@ static size_t nfs_parse_server_name(char *string, size_t len, | |||
137 | 137 | ||
138 | /** | 138 | /** |
139 | * nfs_find_best_sec - Find a security mechanism supported locally | 139 | * nfs_find_best_sec - Find a security mechanism supported locally |
140 | * @server: NFS server struct | ||
140 | * @flavors: List of security tuples returned by SECINFO procedure | 141 | * @flavors: List of security tuples returned by SECINFO procedure |
141 | * | 142 | * |
142 | * Return the pseudoflavor of the first security mechanism in | 143 | * Return the pseudoflavor of the first security mechanism in |
@@ -145,7 +146,8 @@ static size_t nfs_parse_server_name(char *string, size_t len, | |||
145 | * is searched in the order returned from the server, per RFC 3530 | 146 | * is searched in the order returned from the server, per RFC 3530 |
146 | * recommendation. | 147 | * recommendation. |
147 | */ | 148 | */ |
148 | rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors) | 149 | static rpc_authflavor_t nfs_find_best_sec(struct nfs_server *server, |
150 | struct nfs4_secinfo_flavors *flavors) | ||
149 | { | 151 | { |
150 | rpc_authflavor_t pseudoflavor; | 152 | rpc_authflavor_t pseudoflavor; |
151 | struct nfs4_secinfo4 *secinfo; | 153 | struct nfs4_secinfo4 *secinfo; |
@@ -160,12 +162,19 @@ rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors) | |||
160 | case RPC_AUTH_GSS: | 162 | case RPC_AUTH_GSS: |
161 | pseudoflavor = rpcauth_get_pseudoflavor(secinfo->flavor, | 163 | pseudoflavor = rpcauth_get_pseudoflavor(secinfo->flavor, |
162 | &secinfo->flavor_info); | 164 | &secinfo->flavor_info); |
163 | if (pseudoflavor != RPC_AUTH_MAXFLAVOR) | 165 | /* make sure pseudoflavor matches sec= mount opt */ |
166 | if (pseudoflavor != RPC_AUTH_MAXFLAVOR && | ||
167 | nfs_auth_info_match(&server->auth_info, | ||
168 | pseudoflavor)) | ||
164 | return pseudoflavor; | 169 | return pseudoflavor; |
165 | break; | 170 | break; |
166 | } | 171 | } |
167 | } | 172 | } |
168 | 173 | ||
174 | /* if there were any sec= options then nothing matched */ | ||
175 | if (server->auth_info.flavor_len > 0) | ||
176 | return -EPERM; | ||
177 | |||
169 | return RPC_AUTH_UNIX; | 178 | return RPC_AUTH_UNIX; |
170 | } | 179 | } |
171 | 180 | ||
@@ -187,7 +196,7 @@ static rpc_authflavor_t nfs4_negotiate_security(struct inode *inode, struct qstr | |||
187 | goto out; | 196 | goto out; |
188 | } | 197 | } |
189 | 198 | ||
190 | flavor = nfs_find_best_sec(flavors); | 199 | flavor = nfs_find_best_sec(NFS_SERVER(inode), flavors); |
191 | 200 | ||
192 | out: | 201 | out: |
193 | put_page(page); | 202 | put_page(page); |
@@ -390,7 +399,7 @@ struct vfsmount *nfs4_submount(struct nfs_server *server, struct dentry *dentry, | |||
390 | 399 | ||
391 | if (client->cl_auth->au_flavor != flavor) | 400 | if (client->cl_auth->au_flavor != flavor) |
392 | flavor = client->cl_auth->au_flavor; | 401 | flavor = client->cl_auth->au_flavor; |
393 | else if (!(server->flags & NFS_MOUNT_SECFLAVOUR)) { | 402 | else { |
394 | rpc_authflavor_t new = nfs4_negotiate_security(dir, name); | 403 | rpc_authflavor_t new = nfs4_negotiate_security(dir, name); |
395 | if ((int)new >= 0) | 404 | if ((int)new >= 0) |
396 | flavor = new; | 405 | flavor = new; |
@@ -400,3 +409,104 @@ out: | |||
400 | rpc_shutdown_client(client); | 409 | rpc_shutdown_client(client); |
401 | return mnt; | 410 | return mnt; |
402 | } | 411 | } |
412 | |||
413 | /* | ||
414 | * Try one location from the fs_locations array. | ||
415 | * | ||
416 | * Returns zero on success, or a negative errno value. | ||
417 | */ | ||
418 | static int nfs4_try_replacing_one_location(struct nfs_server *server, | ||
419 | char *page, char *page2, | ||
420 | const struct nfs4_fs_location *location) | ||
421 | { | ||
422 | const size_t addr_bufsize = sizeof(struct sockaddr_storage); | ||
423 | struct sockaddr *sap; | ||
424 | unsigned int s; | ||
425 | size_t salen; | ||
426 | int error; | ||
427 | |||
428 | sap = kmalloc(addr_bufsize, GFP_KERNEL); | ||
429 | if (sap == NULL) | ||
430 | return -ENOMEM; | ||
431 | |||
432 | error = -ENOENT; | ||
433 | for (s = 0; s < location->nservers; s++) { | ||
434 | const struct nfs4_string *buf = &location->servers[s]; | ||
435 | char *hostname; | ||
436 | |||
437 | if (buf->len <= 0 || buf->len > PAGE_SIZE) | ||
438 | continue; | ||
439 | |||
440 | if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len) != NULL) | ||
441 | continue; | ||
442 | |||
443 | salen = nfs_parse_server_name(buf->data, buf->len, | ||
444 | sap, addr_bufsize, server); | ||
445 | if (salen == 0) | ||
446 | continue; | ||
447 | rpc_set_port(sap, NFS_PORT); | ||
448 | |||
449 | error = -ENOMEM; | ||
450 | hostname = kstrndup(buf->data, buf->len, GFP_KERNEL); | ||
451 | if (hostname == NULL) | ||
452 | break; | ||
453 | |||
454 | error = nfs4_update_server(server, hostname, sap, salen); | ||
455 | kfree(hostname); | ||
456 | if (error == 0) | ||
457 | break; | ||
458 | } | ||
459 | |||
460 | kfree(sap); | ||
461 | return error; | ||
462 | } | ||
463 | |||
464 | /** | ||
465 | * nfs4_replace_transport - set up transport to destination server | ||
466 | * | ||
467 | * @server: export being migrated | ||
468 | * @locations: fs_locations array | ||
469 | * | ||
470 | * Returns zero on success, or a negative errno value. | ||
471 | * | ||
472 | * The client tries all the entries in the "locations" array, in the | ||
473 | * order returned by the server, until one works or the end of the | ||
474 | * array is reached. | ||
475 | */ | ||
476 | int nfs4_replace_transport(struct nfs_server *server, | ||
477 | const struct nfs4_fs_locations *locations) | ||
478 | { | ||
479 | char *page = NULL, *page2 = NULL; | ||
480 | int loc, error; | ||
481 | |||
482 | error = -ENOENT; | ||
483 | if (locations == NULL || locations->nlocations <= 0) | ||
484 | goto out; | ||
485 | |||
486 | error = -ENOMEM; | ||
487 | page = (char *) __get_free_page(GFP_USER); | ||
488 | if (!page) | ||
489 | goto out; | ||
490 | page2 = (char *) __get_free_page(GFP_USER); | ||
491 | if (!page2) | ||
492 | goto out; | ||
493 | |||
494 | for (loc = 0; loc < locations->nlocations; loc++) { | ||
495 | const struct nfs4_fs_location *location = | ||
496 | &locations->locations[loc]; | ||
497 | |||
498 | if (location == NULL || location->nservers <= 0 || | ||
499 | location->rootpath.ncomponents == 0) | ||
500 | continue; | ||
501 | |||
502 | error = nfs4_try_replacing_one_location(server, page, | ||
503 | page2, location); | ||
504 | if (error == 0) | ||
505 | break; | ||
506 | } | ||
507 | |||
508 | out: | ||
509 | free_page((unsigned long)page); | ||
510 | free_page((unsigned long)page2); | ||
511 | return error; | ||
512 | } | ||
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index d53d6785cba2..5ab33c0792df 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -105,9 +105,6 @@ nfs4_label_init_security(struct inode *dir, struct dentry *dentry, | |||
105 | if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL) == 0) | 105 | if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL) == 0) |
106 | return NULL; | 106 | return NULL; |
107 | 107 | ||
108 | if (NFS_SERVER(dir)->nfs_client->cl_minorversion < 2) | ||
109 | return NULL; | ||
110 | |||
111 | err = security_dentry_init_security(dentry, sattr->ia_mode, | 108 | err = security_dentry_init_security(dentry, sattr->ia_mode, |
112 | &dentry->d_name, (void **)&label->label, &label->len); | 109 | &dentry->d_name, (void **)&label->label, &label->len); |
113 | if (err == 0) | 110 | if (err == 0) |
@@ -384,6 +381,14 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc | |||
384 | case -NFS4ERR_STALE_CLIENTID: | 381 | case -NFS4ERR_STALE_CLIENTID: |
385 | nfs4_schedule_lease_recovery(clp); | 382 | nfs4_schedule_lease_recovery(clp); |
386 | goto wait_on_recovery; | 383 | goto wait_on_recovery; |
384 | case -NFS4ERR_MOVED: | ||
385 | ret = nfs4_schedule_migration_recovery(server); | ||
386 | if (ret < 0) | ||
387 | break; | ||
388 | goto wait_on_recovery; | ||
389 | case -NFS4ERR_LEASE_MOVED: | ||
390 | nfs4_schedule_lease_moved_recovery(clp); | ||
391 | goto wait_on_recovery; | ||
387 | #if defined(CONFIG_NFS_V4_1) | 392 | #if defined(CONFIG_NFS_V4_1) |
388 | case -NFS4ERR_BADSESSION: | 393 | case -NFS4ERR_BADSESSION: |
389 | case -NFS4ERR_BADSLOT: | 394 | case -NFS4ERR_BADSLOT: |
@@ -431,6 +436,8 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc | |||
431 | return nfs4_map_errors(ret); | 436 | return nfs4_map_errors(ret); |
432 | wait_on_recovery: | 437 | wait_on_recovery: |
433 | ret = nfs4_wait_clnt_recover(clp); | 438 | ret = nfs4_wait_clnt_recover(clp); |
439 | if (test_bit(NFS_MIG_FAILED, &server->mig_status)) | ||
440 | return -EIO; | ||
434 | if (ret == 0) | 441 | if (ret == 0) |
435 | exception->retry = 1; | 442 | exception->retry = 1; |
436 | return ret; | 443 | return ret; |
@@ -1318,31 +1325,24 @@ _nfs4_opendata_reclaim_to_nfs4_state(struct nfs4_opendata *data) | |||
1318 | int ret; | 1325 | int ret; |
1319 | 1326 | ||
1320 | if (!data->rpc_done) { | 1327 | if (!data->rpc_done) { |
1321 | ret = data->rpc_status; | 1328 | if (data->rpc_status) { |
1322 | goto err; | 1329 | ret = data->rpc_status; |
1330 | goto err; | ||
1331 | } | ||
1332 | /* cached opens have already been processed */ | ||
1333 | goto update; | ||
1323 | } | 1334 | } |
1324 | 1335 | ||
1325 | ret = -ESTALE; | ||
1326 | if (!(data->f_attr.valid & NFS_ATTR_FATTR_TYPE) || | ||
1327 | !(data->f_attr.valid & NFS_ATTR_FATTR_FILEID) || | ||
1328 | !(data->f_attr.valid & NFS_ATTR_FATTR_CHANGE)) | ||
1329 | goto err; | ||
1330 | |||
1331 | ret = -ENOMEM; | ||
1332 | state = nfs4_get_open_state(inode, data->owner); | ||
1333 | if (state == NULL) | ||
1334 | goto err; | ||
1335 | |||
1336 | ret = nfs_refresh_inode(inode, &data->f_attr); | 1336 | ret = nfs_refresh_inode(inode, &data->f_attr); |
1337 | if (ret) | 1337 | if (ret) |
1338 | goto err; | 1338 | goto err; |
1339 | 1339 | ||
1340 | nfs_setsecurity(inode, &data->f_attr, data->f_label); | ||
1341 | |||
1342 | if (data->o_res.delegation_type != 0) | 1340 | if (data->o_res.delegation_type != 0) |
1343 | nfs4_opendata_check_deleg(data, state); | 1341 | nfs4_opendata_check_deleg(data, state); |
1342 | update: | ||
1344 | update_open_stateid(state, &data->o_res.stateid, NULL, | 1343 | update_open_stateid(state, &data->o_res.stateid, NULL, |
1345 | data->o_arg.fmode); | 1344 | data->o_arg.fmode); |
1345 | atomic_inc(&state->count); | ||
1346 | 1346 | ||
1347 | return state; | 1347 | return state; |
1348 | err: | 1348 | err: |
@@ -1575,6 +1575,12 @@ static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct | |||
1575 | /* Don't recall a delegation if it was lost */ | 1575 | /* Don't recall a delegation if it was lost */ |
1576 | nfs4_schedule_lease_recovery(server->nfs_client); | 1576 | nfs4_schedule_lease_recovery(server->nfs_client); |
1577 | return -EAGAIN; | 1577 | return -EAGAIN; |
1578 | case -NFS4ERR_MOVED: | ||
1579 | nfs4_schedule_migration_recovery(server); | ||
1580 | return -EAGAIN; | ||
1581 | case -NFS4ERR_LEASE_MOVED: | ||
1582 | nfs4_schedule_lease_moved_recovery(server->nfs_client); | ||
1583 | return -EAGAIN; | ||
1578 | case -NFS4ERR_DELEG_REVOKED: | 1584 | case -NFS4ERR_DELEG_REVOKED: |
1579 | case -NFS4ERR_ADMIN_REVOKED: | 1585 | case -NFS4ERR_ADMIN_REVOKED: |
1580 | case -NFS4ERR_BAD_STATEID: | 1586 | case -NFS4ERR_BAD_STATEID: |
@@ -2697,6 +2703,10 @@ static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync) | |||
2697 | nfs4_close_state(ctx->state, ctx->mode); | 2703 | nfs4_close_state(ctx->state, ctx->mode); |
2698 | } | 2704 | } |
2699 | 2705 | ||
2706 | #define FATTR4_WORD1_NFS40_MASK (2*FATTR4_WORD1_MOUNTED_ON_FILEID - 1UL) | ||
2707 | #define FATTR4_WORD2_NFS41_MASK (2*FATTR4_WORD2_SUPPATTR_EXCLCREAT - 1UL) | ||
2708 | #define FATTR4_WORD2_NFS42_MASK (2*FATTR4_WORD2_CHANGE_SECURITY_LABEL - 1UL) | ||
2709 | |||
2700 | static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) | 2710 | static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) |
2701 | { | 2711 | { |
2702 | struct nfs4_server_caps_arg args = { | 2712 | struct nfs4_server_caps_arg args = { |
@@ -2712,12 +2722,25 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f | |||
2712 | 2722 | ||
2713 | status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); | 2723 | status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); |
2714 | if (status == 0) { | 2724 | if (status == 0) { |
2725 | /* Sanity check the server answers */ | ||
2726 | switch (server->nfs_client->cl_minorversion) { | ||
2727 | case 0: | ||
2728 | res.attr_bitmask[1] &= FATTR4_WORD1_NFS40_MASK; | ||
2729 | res.attr_bitmask[2] = 0; | ||
2730 | break; | ||
2731 | case 1: | ||
2732 | res.attr_bitmask[2] &= FATTR4_WORD2_NFS41_MASK; | ||
2733 | break; | ||
2734 | case 2: | ||
2735 | res.attr_bitmask[2] &= FATTR4_WORD2_NFS42_MASK; | ||
2736 | } | ||
2715 | memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); | 2737 | memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); |
2716 | server->caps &= ~(NFS_CAP_ACLS|NFS_CAP_HARDLINKS| | 2738 | server->caps &= ~(NFS_CAP_ACLS|NFS_CAP_HARDLINKS| |
2717 | NFS_CAP_SYMLINKS|NFS_CAP_FILEID| | 2739 | NFS_CAP_SYMLINKS|NFS_CAP_FILEID| |
2718 | NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER| | 2740 | NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER| |
2719 | NFS_CAP_OWNER_GROUP|NFS_CAP_ATIME| | 2741 | NFS_CAP_OWNER_GROUP|NFS_CAP_ATIME| |
2720 | NFS_CAP_CTIME|NFS_CAP_MTIME); | 2742 | NFS_CAP_CTIME|NFS_CAP_MTIME| |
2743 | NFS_CAP_SECURITY_LABEL); | ||
2721 | if (res.attr_bitmask[0] & FATTR4_WORD0_ACL) | 2744 | if (res.attr_bitmask[0] & FATTR4_WORD0_ACL) |
2722 | server->caps |= NFS_CAP_ACLS; | 2745 | server->caps |= NFS_CAP_ACLS; |
2723 | if (res.has_links != 0) | 2746 | if (res.has_links != 0) |
@@ -2746,14 +2769,12 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f | |||
2746 | #endif | 2769 | #endif |
2747 | memcpy(server->attr_bitmask_nl, res.attr_bitmask, | 2770 | memcpy(server->attr_bitmask_nl, res.attr_bitmask, |
2748 | sizeof(server->attr_bitmask)); | 2771 | sizeof(server->attr_bitmask)); |
2772 | server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL; | ||
2749 | 2773 | ||
2750 | if (server->caps & NFS_CAP_SECURITY_LABEL) { | ||
2751 | server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL; | ||
2752 | res.attr_bitmask[2] &= ~FATTR4_WORD2_SECURITY_LABEL; | ||
2753 | } | ||
2754 | memcpy(server->cache_consistency_bitmask, res.attr_bitmask, sizeof(server->cache_consistency_bitmask)); | 2774 | memcpy(server->cache_consistency_bitmask, res.attr_bitmask, sizeof(server->cache_consistency_bitmask)); |
2755 | server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE; | 2775 | server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE; |
2756 | server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; | 2776 | server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; |
2777 | server->cache_consistency_bitmask[2] = 0; | ||
2757 | server->acl_bitmask = res.acl_bitmask; | 2778 | server->acl_bitmask = res.acl_bitmask; |
2758 | server->fh_expire_type = res.fh_expire_type; | 2779 | server->fh_expire_type = res.fh_expire_type; |
2759 | } | 2780 | } |
@@ -2864,11 +2885,24 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2864 | int status = -EPERM; | 2885 | int status = -EPERM; |
2865 | size_t i; | 2886 | size_t i; |
2866 | 2887 | ||
2867 | for (i = 0; i < ARRAY_SIZE(flav_array); i++) { | 2888 | if (server->auth_info.flavor_len > 0) { |
2868 | status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]); | 2889 | /* try each flavor specified by user */ |
2869 | if (status == -NFS4ERR_WRONGSEC || status == -EACCES) | 2890 | for (i = 0; i < server->auth_info.flavor_len; i++) { |
2870 | continue; | 2891 | status = nfs4_lookup_root_sec(server, fhandle, info, |
2871 | break; | 2892 | server->auth_info.flavors[i]); |
2893 | if (status == -NFS4ERR_WRONGSEC || status == -EACCES) | ||
2894 | continue; | ||
2895 | break; | ||
2896 | } | ||
2897 | } else { | ||
2898 | /* no flavors specified by user, try default list */ | ||
2899 | for (i = 0; i < ARRAY_SIZE(flav_array); i++) { | ||
2900 | status = nfs4_lookup_root_sec(server, fhandle, info, | ||
2901 | flav_array[i]); | ||
2902 | if (status == -NFS4ERR_WRONGSEC || status == -EACCES) | ||
2903 | continue; | ||
2904 | break; | ||
2905 | } | ||
2872 | } | 2906 | } |
2873 | 2907 | ||
2874 | /* | 2908 | /* |
@@ -2910,9 +2944,6 @@ int nfs4_proc_get_rootfh(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2910 | status = nfs4_lookup_root(server, fhandle, info); | 2944 | status = nfs4_lookup_root(server, fhandle, info); |
2911 | if (status != -NFS4ERR_WRONGSEC) | 2945 | if (status != -NFS4ERR_WRONGSEC) |
2912 | break; | 2946 | break; |
2913 | /* Did user force a 'sec=' mount option? */ | ||
2914 | if (server->flags & NFS_MOUNT_SECFLAVOUR) | ||
2915 | break; | ||
2916 | default: | 2947 | default: |
2917 | status = nfs4_do_find_root_sec(server, fhandle, info); | 2948 | status = nfs4_do_find_root_sec(server, fhandle, info); |
2918 | } | 2949 | } |
@@ -2981,11 +3012,16 @@ static int nfs4_get_referral(struct rpc_clnt *client, struct inode *dir, | |||
2981 | status = nfs4_proc_fs_locations(client, dir, name, locations, page); | 3012 | status = nfs4_proc_fs_locations(client, dir, name, locations, page); |
2982 | if (status != 0) | 3013 | if (status != 0) |
2983 | goto out; | 3014 | goto out; |
2984 | /* Make sure server returned a different fsid for the referral */ | 3015 | |
3016 | /* | ||
3017 | * If the fsid didn't change, this is a migration event, not a | ||
3018 | * referral. Cause us to drop into the exception handler, which | ||
3019 | * will kick off migration recovery. | ||
3020 | */ | ||
2985 | if (nfs_fsid_equal(&NFS_SERVER(dir)->fsid, &locations->fattr.fsid)) { | 3021 | if (nfs_fsid_equal(&NFS_SERVER(dir)->fsid, &locations->fattr.fsid)) { |
2986 | dprintk("%s: server did not return a different fsid for" | 3022 | dprintk("%s: server did not return a different fsid for" |
2987 | " a referral at %s\n", __func__, name->name); | 3023 | " a referral at %s\n", __func__, name->name); |
2988 | status = -EIO; | 3024 | status = -NFS4ERR_MOVED; |
2989 | goto out; | 3025 | goto out; |
2990 | } | 3026 | } |
2991 | /* Fixup attributes for the nfs_lookup() call to nfs_fhget() */ | 3027 | /* Fixup attributes for the nfs_lookup() call to nfs_fhget() */ |
@@ -3165,9 +3201,6 @@ static int nfs4_proc_lookup_common(struct rpc_clnt **clnt, struct inode *dir, | |||
3165 | err = -EPERM; | 3201 | err = -EPERM; |
3166 | if (client != *clnt) | 3202 | if (client != *clnt) |
3167 | goto out; | 3203 | goto out; |
3168 | /* No security negotiation if the user specified 'sec=' */ | ||
3169 | if (NFS_SERVER(dir)->flags & NFS_MOUNT_SECFLAVOUR) | ||
3170 | goto out; | ||
3171 | client = nfs4_create_sec_client(client, dir, name); | 3204 | client = nfs4_create_sec_client(client, dir, name); |
3172 | if (IS_ERR(client)) | 3205 | if (IS_ERR(client)) |
3173 | return PTR_ERR(client); | 3206 | return PTR_ERR(client); |
@@ -4221,7 +4254,13 @@ static void nfs4_renew_done(struct rpc_task *task, void *calldata) | |||
4221 | unsigned long timestamp = data->timestamp; | 4254 | unsigned long timestamp = data->timestamp; |
4222 | 4255 | ||
4223 | trace_nfs4_renew_async(clp, task->tk_status); | 4256 | trace_nfs4_renew_async(clp, task->tk_status); |
4224 | if (task->tk_status < 0) { | 4257 | switch (task->tk_status) { |
4258 | case 0: | ||
4259 | break; | ||
4260 | case -NFS4ERR_LEASE_MOVED: | ||
4261 | nfs4_schedule_lease_moved_recovery(clp); | ||
4262 | break; | ||
4263 | default: | ||
4225 | /* Unless we're shutting down, schedule state recovery! */ | 4264 | /* Unless we're shutting down, schedule state recovery! */ |
4226 | if (test_bit(NFS_CS_RENEWD, &clp->cl_res_state) == 0) | 4265 | if (test_bit(NFS_CS_RENEWD, &clp->cl_res_state) == 0) |
4227 | return; | 4266 | return; |
@@ -4575,7 +4614,7 @@ static int _nfs4_get_security_label(struct inode *inode, void *buf, | |||
4575 | struct nfs4_label label = {0, 0, buflen, buf}; | 4614 | struct nfs4_label label = {0, 0, buflen, buf}; |
4576 | 4615 | ||
4577 | u32 bitmask[3] = { 0, 0, FATTR4_WORD2_SECURITY_LABEL }; | 4616 | u32 bitmask[3] = { 0, 0, FATTR4_WORD2_SECURITY_LABEL }; |
4578 | struct nfs4_getattr_arg args = { | 4617 | struct nfs4_getattr_arg arg = { |
4579 | .fh = NFS_FH(inode), | 4618 | .fh = NFS_FH(inode), |
4580 | .bitmask = bitmask, | 4619 | .bitmask = bitmask, |
4581 | }; | 4620 | }; |
@@ -4586,14 +4625,14 @@ static int _nfs4_get_security_label(struct inode *inode, void *buf, | |||
4586 | }; | 4625 | }; |
4587 | struct rpc_message msg = { | 4626 | struct rpc_message msg = { |
4588 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETATTR], | 4627 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETATTR], |
4589 | .rpc_argp = &args, | 4628 | .rpc_argp = &arg, |
4590 | .rpc_resp = &res, | 4629 | .rpc_resp = &res, |
4591 | }; | 4630 | }; |
4592 | int ret; | 4631 | int ret; |
4593 | 4632 | ||
4594 | nfs_fattr_init(&fattr); | 4633 | nfs_fattr_init(&fattr); |
4595 | 4634 | ||
4596 | ret = rpc_call_sync(server->client, &msg, 0); | 4635 | ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 0); |
4597 | if (ret) | 4636 | if (ret) |
4598 | return ret; | 4637 | return ret; |
4599 | if (!(fattr.valid & NFS_ATTR_FATTR_V4_SECURITY_LABEL)) | 4638 | if (!(fattr.valid & NFS_ATTR_FATTR_V4_SECURITY_LABEL)) |
@@ -4630,7 +4669,7 @@ static int _nfs4_do_set_security_label(struct inode *inode, | |||
4630 | struct iattr sattr = {0}; | 4669 | struct iattr sattr = {0}; |
4631 | struct nfs_server *server = NFS_SERVER(inode); | 4670 | struct nfs_server *server = NFS_SERVER(inode); |
4632 | const u32 bitmask[3] = { 0, 0, FATTR4_WORD2_SECURITY_LABEL }; | 4671 | const u32 bitmask[3] = { 0, 0, FATTR4_WORD2_SECURITY_LABEL }; |
4633 | struct nfs_setattrargs args = { | 4672 | struct nfs_setattrargs arg = { |
4634 | .fh = NFS_FH(inode), | 4673 | .fh = NFS_FH(inode), |
4635 | .iap = &sattr, | 4674 | .iap = &sattr, |
4636 | .server = server, | 4675 | .server = server, |
@@ -4644,14 +4683,14 @@ static int _nfs4_do_set_security_label(struct inode *inode, | |||
4644 | }; | 4683 | }; |
4645 | struct rpc_message msg = { | 4684 | struct rpc_message msg = { |
4646 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETATTR], | 4685 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETATTR], |
4647 | .rpc_argp = &args, | 4686 | .rpc_argp = &arg, |
4648 | .rpc_resp = &res, | 4687 | .rpc_resp = &res, |
4649 | }; | 4688 | }; |
4650 | int status; | 4689 | int status; |
4651 | 4690 | ||
4652 | nfs4_stateid_copy(&args.stateid, &zero_stateid); | 4691 | nfs4_stateid_copy(&arg.stateid, &zero_stateid); |
4653 | 4692 | ||
4654 | status = rpc_call_sync(server->client, &msg, 0); | 4693 | status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); |
4655 | if (status) | 4694 | if (status) |
4656 | dprintk("%s failed: %d\n", __func__, status); | 4695 | dprintk("%s failed: %d\n", __func__, status); |
4657 | 4696 | ||
@@ -4735,17 +4774,24 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
4735 | if (state == NULL) | 4774 | if (state == NULL) |
4736 | break; | 4775 | break; |
4737 | if (nfs4_schedule_stateid_recovery(server, state) < 0) | 4776 | if (nfs4_schedule_stateid_recovery(server, state) < 0) |
4738 | goto stateid_invalid; | 4777 | goto recovery_failed; |
4739 | goto wait_on_recovery; | 4778 | goto wait_on_recovery; |
4740 | case -NFS4ERR_EXPIRED: | 4779 | case -NFS4ERR_EXPIRED: |
4741 | if (state != NULL) { | 4780 | if (state != NULL) { |
4742 | if (nfs4_schedule_stateid_recovery(server, state) < 0) | 4781 | if (nfs4_schedule_stateid_recovery(server, state) < 0) |
4743 | goto stateid_invalid; | 4782 | goto recovery_failed; |
4744 | } | 4783 | } |
4745 | case -NFS4ERR_STALE_STATEID: | 4784 | case -NFS4ERR_STALE_STATEID: |
4746 | case -NFS4ERR_STALE_CLIENTID: | 4785 | case -NFS4ERR_STALE_CLIENTID: |
4747 | nfs4_schedule_lease_recovery(clp); | 4786 | nfs4_schedule_lease_recovery(clp); |
4748 | goto wait_on_recovery; | 4787 | goto wait_on_recovery; |
4788 | case -NFS4ERR_MOVED: | ||
4789 | if (nfs4_schedule_migration_recovery(server) < 0) | ||
4790 | goto recovery_failed; | ||
4791 | goto wait_on_recovery; | ||
4792 | case -NFS4ERR_LEASE_MOVED: | ||
4793 | nfs4_schedule_lease_moved_recovery(clp); | ||
4794 | goto wait_on_recovery; | ||
4749 | #if defined(CONFIG_NFS_V4_1) | 4795 | #if defined(CONFIG_NFS_V4_1) |
4750 | case -NFS4ERR_BADSESSION: | 4796 | case -NFS4ERR_BADSESSION: |
4751 | case -NFS4ERR_BADSLOT: | 4797 | case -NFS4ERR_BADSLOT: |
@@ -4757,29 +4803,28 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
4757 | dprintk("%s ERROR %d, Reset session\n", __func__, | 4803 | dprintk("%s ERROR %d, Reset session\n", __func__, |
4758 | task->tk_status); | 4804 | task->tk_status); |
4759 | nfs4_schedule_session_recovery(clp->cl_session, task->tk_status); | 4805 | nfs4_schedule_session_recovery(clp->cl_session, task->tk_status); |
4760 | task->tk_status = 0; | 4806 | goto restart_call; |
4761 | return -EAGAIN; | ||
4762 | #endif /* CONFIG_NFS_V4_1 */ | 4807 | #endif /* CONFIG_NFS_V4_1 */ |
4763 | case -NFS4ERR_DELAY: | 4808 | case -NFS4ERR_DELAY: |
4764 | nfs_inc_server_stats(server, NFSIOS_DELAY); | 4809 | nfs_inc_server_stats(server, NFSIOS_DELAY); |
4765 | case -NFS4ERR_GRACE: | 4810 | case -NFS4ERR_GRACE: |
4766 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | 4811 | rpc_delay(task, NFS4_POLL_RETRY_MAX); |
4767 | task->tk_status = 0; | ||
4768 | return -EAGAIN; | ||
4769 | case -NFS4ERR_RETRY_UNCACHED_REP: | 4812 | case -NFS4ERR_RETRY_UNCACHED_REP: |
4770 | case -NFS4ERR_OLD_STATEID: | 4813 | case -NFS4ERR_OLD_STATEID: |
4771 | task->tk_status = 0; | 4814 | goto restart_call; |
4772 | return -EAGAIN; | ||
4773 | } | 4815 | } |
4774 | task->tk_status = nfs4_map_errors(task->tk_status); | 4816 | task->tk_status = nfs4_map_errors(task->tk_status); |
4775 | return 0; | 4817 | return 0; |
4776 | stateid_invalid: | 4818 | recovery_failed: |
4777 | task->tk_status = -EIO; | 4819 | task->tk_status = -EIO; |
4778 | return 0; | 4820 | return 0; |
4779 | wait_on_recovery: | 4821 | wait_on_recovery: |
4780 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL); | 4822 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL); |
4781 | if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0) | 4823 | if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0) |
4782 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); | 4824 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); |
4825 | if (test_bit(NFS_MIG_FAILED, &server->mig_status)) | ||
4826 | goto recovery_failed; | ||
4827 | restart_call: | ||
4783 | task->tk_status = 0; | 4828 | task->tk_status = 0; |
4784 | return -EAGAIN; | 4829 | return -EAGAIN; |
4785 | } | 4830 | } |
@@ -5106,6 +5151,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
5106 | status = 0; | 5151 | status = 0; |
5107 | } | 5152 | } |
5108 | request->fl_ops->fl_release_private(request); | 5153 | request->fl_ops->fl_release_private(request); |
5154 | request->fl_ops = NULL; | ||
5109 | out: | 5155 | out: |
5110 | return status; | 5156 | return status; |
5111 | } | 5157 | } |
@@ -5779,6 +5825,7 @@ struct nfs_release_lockowner_data { | |||
5779 | struct nfs_release_lockowner_args args; | 5825 | struct nfs_release_lockowner_args args; |
5780 | struct nfs4_sequence_args seq_args; | 5826 | struct nfs4_sequence_args seq_args; |
5781 | struct nfs4_sequence_res seq_res; | 5827 | struct nfs4_sequence_res seq_res; |
5828 | unsigned long timestamp; | ||
5782 | }; | 5829 | }; |
5783 | 5830 | ||
5784 | static void nfs4_release_lockowner_prepare(struct rpc_task *task, void *calldata) | 5831 | static void nfs4_release_lockowner_prepare(struct rpc_task *task, void *calldata) |
@@ -5786,12 +5833,27 @@ static void nfs4_release_lockowner_prepare(struct rpc_task *task, void *calldata | |||
5786 | struct nfs_release_lockowner_data *data = calldata; | 5833 | struct nfs_release_lockowner_data *data = calldata; |
5787 | nfs40_setup_sequence(data->server, | 5834 | nfs40_setup_sequence(data->server, |
5788 | &data->seq_args, &data->seq_res, task); | 5835 | &data->seq_args, &data->seq_res, task); |
5836 | data->timestamp = jiffies; | ||
5789 | } | 5837 | } |
5790 | 5838 | ||
5791 | static void nfs4_release_lockowner_done(struct rpc_task *task, void *calldata) | 5839 | static void nfs4_release_lockowner_done(struct rpc_task *task, void *calldata) |
5792 | { | 5840 | { |
5793 | struct nfs_release_lockowner_data *data = calldata; | 5841 | struct nfs_release_lockowner_data *data = calldata; |
5842 | struct nfs_server *server = data->server; | ||
5843 | |||
5794 | nfs40_sequence_done(task, &data->seq_res); | 5844 | nfs40_sequence_done(task, &data->seq_res); |
5845 | |||
5846 | switch (task->tk_status) { | ||
5847 | case 0: | ||
5848 | renew_lease(server, data->timestamp); | ||
5849 | break; | ||
5850 | case -NFS4ERR_STALE_CLIENTID: | ||
5851 | case -NFS4ERR_EXPIRED: | ||
5852 | case -NFS4ERR_LEASE_MOVED: | ||
5853 | case -NFS4ERR_DELAY: | ||
5854 | if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) | ||
5855 | rpc_restart_call_prepare(task); | ||
5856 | } | ||
5795 | } | 5857 | } |
5796 | 5858 | ||
5797 | static void nfs4_release_lockowner_release(void *calldata) | 5859 | static void nfs4_release_lockowner_release(void *calldata) |
@@ -5990,6 +6052,283 @@ int nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir, | |||
5990 | return err; | 6052 | return err; |
5991 | } | 6053 | } |
5992 | 6054 | ||
6055 | /* | ||
6056 | * This operation also signals the server that this client is | ||
6057 | * performing migration recovery. The server can stop returning | ||
6058 | * NFS4ERR_LEASE_MOVED to this client. A RENEW operation is | ||
6059 | * appended to this compound to identify the client ID which is | ||
6060 | * performing recovery. | ||
6061 | */ | ||
6062 | static int _nfs40_proc_get_locations(struct inode *inode, | ||
6063 | struct nfs4_fs_locations *locations, | ||
6064 | struct page *page, struct rpc_cred *cred) | ||
6065 | { | ||
6066 | struct nfs_server *server = NFS_SERVER(inode); | ||
6067 | struct rpc_clnt *clnt = server->client; | ||
6068 | u32 bitmask[2] = { | ||
6069 | [0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS, | ||
6070 | }; | ||
6071 | struct nfs4_fs_locations_arg args = { | ||
6072 | .clientid = server->nfs_client->cl_clientid, | ||
6073 | .fh = NFS_FH(inode), | ||
6074 | .page = page, | ||
6075 | .bitmask = bitmask, | ||
6076 | .migration = 1, /* skip LOOKUP */ | ||
6077 | .renew = 1, /* append RENEW */ | ||
6078 | }; | ||
6079 | struct nfs4_fs_locations_res res = { | ||
6080 | .fs_locations = locations, | ||
6081 | .migration = 1, | ||
6082 | .renew = 1, | ||
6083 | }; | ||
6084 | struct rpc_message msg = { | ||
6085 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS], | ||
6086 | .rpc_argp = &args, | ||
6087 | .rpc_resp = &res, | ||
6088 | .rpc_cred = cred, | ||
6089 | }; | ||
6090 | unsigned long now = jiffies; | ||
6091 | int status; | ||
6092 | |||
6093 | nfs_fattr_init(&locations->fattr); | ||
6094 | locations->server = server; | ||
6095 | locations->nlocations = 0; | ||
6096 | |||
6097 | nfs4_init_sequence(&args.seq_args, &res.seq_res, 0); | ||
6098 | nfs4_set_sequence_privileged(&args.seq_args); | ||
6099 | status = nfs4_call_sync_sequence(clnt, server, &msg, | ||
6100 | &args.seq_args, &res.seq_res); | ||
6101 | if (status) | ||
6102 | return status; | ||
6103 | |||
6104 | renew_lease(server, now); | ||
6105 | return 0; | ||
6106 | } | ||
6107 | |||
6108 | #ifdef CONFIG_NFS_V4_1 | ||
6109 | |||
6110 | /* | ||
6111 | * This operation also signals the server that this client is | ||
6112 | * performing migration recovery. The server can stop asserting | ||
6113 | * SEQ4_STATUS_LEASE_MOVED for this client. The client ID | ||
6114 | * performing this operation is identified in the SEQUENCE | ||
6115 | * operation in this compound. | ||
6116 | * | ||
6117 | * When the client supports GETATTR(fs_locations_info), it can | ||
6118 | * be plumbed in here. | ||
6119 | */ | ||
6120 | static int _nfs41_proc_get_locations(struct inode *inode, | ||
6121 | struct nfs4_fs_locations *locations, | ||
6122 | struct page *page, struct rpc_cred *cred) | ||
6123 | { | ||
6124 | struct nfs_server *server = NFS_SERVER(inode); | ||
6125 | struct rpc_clnt *clnt = server->client; | ||
6126 | u32 bitmask[2] = { | ||
6127 | [0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS, | ||
6128 | }; | ||
6129 | struct nfs4_fs_locations_arg args = { | ||
6130 | .fh = NFS_FH(inode), | ||
6131 | .page = page, | ||
6132 | .bitmask = bitmask, | ||
6133 | .migration = 1, /* skip LOOKUP */ | ||
6134 | }; | ||
6135 | struct nfs4_fs_locations_res res = { | ||
6136 | .fs_locations = locations, | ||
6137 | .migration = 1, | ||
6138 | }; | ||
6139 | struct rpc_message msg = { | ||
6140 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS], | ||
6141 | .rpc_argp = &args, | ||
6142 | .rpc_resp = &res, | ||
6143 | .rpc_cred = cred, | ||
6144 | }; | ||
6145 | int status; | ||
6146 | |||
6147 | nfs_fattr_init(&locations->fattr); | ||
6148 | locations->server = server; | ||
6149 | locations->nlocations = 0; | ||
6150 | |||
6151 | nfs4_init_sequence(&args.seq_args, &res.seq_res, 0); | ||
6152 | nfs4_set_sequence_privileged(&args.seq_args); | ||
6153 | status = nfs4_call_sync_sequence(clnt, server, &msg, | ||
6154 | &args.seq_args, &res.seq_res); | ||
6155 | if (status == NFS4_OK && | ||
6156 | res.seq_res.sr_status_flags & SEQ4_STATUS_LEASE_MOVED) | ||
6157 | status = -NFS4ERR_LEASE_MOVED; | ||
6158 | return status; | ||
6159 | } | ||
6160 | |||
6161 | #endif /* CONFIG_NFS_V4_1 */ | ||
6162 | |||
6163 | /** | ||
6164 | * nfs4_proc_get_locations - discover locations for a migrated FSID | ||
6165 | * @inode: inode on FSID that is migrating | ||
6166 | * @locations: result of query | ||
6167 | * @page: buffer | ||
6168 | * @cred: credential to use for this operation | ||
6169 | * | ||
6170 | * Returns NFS4_OK on success, a negative NFS4ERR status code if the | ||
6171 | * operation failed, or a negative errno if a local error occurred. | ||
6172 | * | ||
6173 | * On success, "locations" is filled in, but if the server has | ||
6174 | * no locations information, NFS_ATTR_FATTR_V4_LOCATIONS is not | ||
6175 | * asserted. | ||
6176 | * | ||
6177 | * -NFS4ERR_LEASE_MOVED is returned if the server still has leases | ||
6178 | * from this client that require migration recovery. | ||
6179 | */ | ||
6180 | int nfs4_proc_get_locations(struct inode *inode, | ||
6181 | struct nfs4_fs_locations *locations, | ||
6182 | struct page *page, struct rpc_cred *cred) | ||
6183 | { | ||
6184 | struct nfs_server *server = NFS_SERVER(inode); | ||
6185 | struct nfs_client *clp = server->nfs_client; | ||
6186 | const struct nfs4_mig_recovery_ops *ops = | ||
6187 | clp->cl_mvops->mig_recovery_ops; | ||
6188 | struct nfs4_exception exception = { }; | ||
6189 | int status; | ||
6190 | |||
6191 | dprintk("%s: FSID %llx:%llx on \"%s\"\n", __func__, | ||
6192 | (unsigned long long)server->fsid.major, | ||
6193 | (unsigned long long)server->fsid.minor, | ||
6194 | clp->cl_hostname); | ||
6195 | nfs_display_fhandle(NFS_FH(inode), __func__); | ||
6196 | |||
6197 | do { | ||
6198 | status = ops->get_locations(inode, locations, page, cred); | ||
6199 | if (status != -NFS4ERR_DELAY) | ||
6200 | break; | ||
6201 | nfs4_handle_exception(server, status, &exception); | ||
6202 | } while (exception.retry); | ||
6203 | return status; | ||
6204 | } | ||
6205 | |||
6206 | /* | ||
6207 | * This operation also signals the server that this client is | ||
6208 | * performing "lease moved" recovery. The server can stop | ||
6209 | * returning NFS4ERR_LEASE_MOVED to this client. A RENEW operation | ||
6210 | * is appended to this compound to identify the client ID which is | ||
6211 | * performing recovery. | ||
6212 | */ | ||
6213 | static int _nfs40_proc_fsid_present(struct inode *inode, struct rpc_cred *cred) | ||
6214 | { | ||
6215 | struct nfs_server *server = NFS_SERVER(inode); | ||
6216 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; | ||
6217 | struct rpc_clnt *clnt = server->client; | ||
6218 | struct nfs4_fsid_present_arg args = { | ||
6219 | .fh = NFS_FH(inode), | ||
6220 | .clientid = clp->cl_clientid, | ||
6221 | .renew = 1, /* append RENEW */ | ||
6222 | }; | ||
6223 | struct nfs4_fsid_present_res res = { | ||
6224 | .renew = 1, | ||
6225 | }; | ||
6226 | struct rpc_message msg = { | ||
6227 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSID_PRESENT], | ||
6228 | .rpc_argp = &args, | ||
6229 | .rpc_resp = &res, | ||
6230 | .rpc_cred = cred, | ||
6231 | }; | ||
6232 | unsigned long now = jiffies; | ||
6233 | int status; | ||
6234 | |||
6235 | res.fh = nfs_alloc_fhandle(); | ||
6236 | if (res.fh == NULL) | ||
6237 | return -ENOMEM; | ||
6238 | |||
6239 | nfs4_init_sequence(&args.seq_args, &res.seq_res, 0); | ||
6240 | nfs4_set_sequence_privileged(&args.seq_args); | ||
6241 | status = nfs4_call_sync_sequence(clnt, server, &msg, | ||
6242 | &args.seq_args, &res.seq_res); | ||
6243 | nfs_free_fhandle(res.fh); | ||
6244 | if (status) | ||
6245 | return status; | ||
6246 | |||
6247 | do_renew_lease(clp, now); | ||
6248 | return 0; | ||
6249 | } | ||
6250 | |||
6251 | #ifdef CONFIG_NFS_V4_1 | ||
6252 | |||
6253 | /* | ||
6254 | * This operation also signals the server that this client is | ||
6255 | * performing "lease moved" recovery. The server can stop asserting | ||
6256 | * SEQ4_STATUS_LEASE_MOVED for this client. The client ID performing | ||
6257 | * this operation is identified in the SEQUENCE operation in this | ||
6258 | * compound. | ||
6259 | */ | ||
6260 | static int _nfs41_proc_fsid_present(struct inode *inode, struct rpc_cred *cred) | ||
6261 | { | ||
6262 | struct nfs_server *server = NFS_SERVER(inode); | ||
6263 | struct rpc_clnt *clnt = server->client; | ||
6264 | struct nfs4_fsid_present_arg args = { | ||
6265 | .fh = NFS_FH(inode), | ||
6266 | }; | ||
6267 | struct nfs4_fsid_present_res res = { | ||
6268 | }; | ||
6269 | struct rpc_message msg = { | ||
6270 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSID_PRESENT], | ||
6271 | .rpc_argp = &args, | ||
6272 | .rpc_resp = &res, | ||
6273 | .rpc_cred = cred, | ||
6274 | }; | ||
6275 | int status; | ||
6276 | |||
6277 | res.fh = nfs_alloc_fhandle(); | ||
6278 | if (res.fh == NULL) | ||
6279 | return -ENOMEM; | ||
6280 | |||
6281 | nfs4_init_sequence(&args.seq_args, &res.seq_res, 0); | ||
6282 | nfs4_set_sequence_privileged(&args.seq_args); | ||
6283 | status = nfs4_call_sync_sequence(clnt, server, &msg, | ||
6284 | &args.seq_args, &res.seq_res); | ||
6285 | nfs_free_fhandle(res.fh); | ||
6286 | if (status == NFS4_OK && | ||
6287 | res.seq_res.sr_status_flags & SEQ4_STATUS_LEASE_MOVED) | ||
6288 | status = -NFS4ERR_LEASE_MOVED; | ||
6289 | return status; | ||
6290 | } | ||
6291 | |||
6292 | #endif /* CONFIG_NFS_V4_1 */ | ||
6293 | |||
6294 | /** | ||
6295 | * nfs4_proc_fsid_present - Is this FSID present or absent on server? | ||
6296 | * @inode: inode on FSID to check | ||
6297 | * @cred: credential to use for this operation | ||
6298 | * | ||
6299 | * Server indicates whether the FSID is present, moved, or not | ||
6300 | * recognized. This operation is necessary to clear a LEASE_MOVED | ||
6301 | * condition for this client ID. | ||
6302 | * | ||
6303 | * Returns NFS4_OK if the FSID is present on this server, | ||
6304 | * -NFS4ERR_MOVED if the FSID is no longer present, a negative | ||
6305 | * NFS4ERR code if some error occurred on the server, or a | ||
6306 | * negative errno if a local failure occurred. | ||
6307 | */ | ||
6308 | int nfs4_proc_fsid_present(struct inode *inode, struct rpc_cred *cred) | ||
6309 | { | ||
6310 | struct nfs_server *server = NFS_SERVER(inode); | ||
6311 | struct nfs_client *clp = server->nfs_client; | ||
6312 | const struct nfs4_mig_recovery_ops *ops = | ||
6313 | clp->cl_mvops->mig_recovery_ops; | ||
6314 | struct nfs4_exception exception = { }; | ||
6315 | int status; | ||
6316 | |||
6317 | dprintk("%s: FSID %llx:%llx on \"%s\"\n", __func__, | ||
6318 | (unsigned long long)server->fsid.major, | ||
6319 | (unsigned long long)server->fsid.minor, | ||
6320 | clp->cl_hostname); | ||
6321 | nfs_display_fhandle(NFS_FH(inode), __func__); | ||
6322 | |||
6323 | do { | ||
6324 | status = ops->fsid_present(inode, cred); | ||
6325 | if (status != -NFS4ERR_DELAY) | ||
6326 | break; | ||
6327 | nfs4_handle_exception(server, status, &exception); | ||
6328 | } while (exception.retry); | ||
6329 | return status; | ||
6330 | } | ||
6331 | |||
5993 | /** | 6332 | /** |
5994 | * If 'use_integrity' is true and the state managment nfs_client | 6333 | * If 'use_integrity' is true and the state managment nfs_client |
5995 | * cl_rpcclient is using krb5i/p, use the integrity protected cl_rpcclient | 6334 | * cl_rpcclient is using krb5i/p, use the integrity protected cl_rpcclient |
@@ -6276,8 +6615,14 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred, | |||
6276 | struct nfs41_exchange_id_args args = { | 6615 | struct nfs41_exchange_id_args args = { |
6277 | .verifier = &verifier, | 6616 | .verifier = &verifier, |
6278 | .client = clp, | 6617 | .client = clp, |
6618 | #ifdef CONFIG_NFS_V4_1_MIGRATION | ||
6279 | .flags = EXCHGID4_FLAG_SUPP_MOVED_REFER | | 6619 | .flags = EXCHGID4_FLAG_SUPP_MOVED_REFER | |
6280 | EXCHGID4_FLAG_BIND_PRINC_STATEID, | 6620 | EXCHGID4_FLAG_BIND_PRINC_STATEID | |
6621 | EXCHGID4_FLAG_SUPP_MOVED_MIGR, | ||
6622 | #else | ||
6623 | .flags = EXCHGID4_FLAG_SUPP_MOVED_REFER | | ||
6624 | EXCHGID4_FLAG_BIND_PRINC_STATEID, | ||
6625 | #endif | ||
6281 | }; | 6626 | }; |
6282 | struct nfs41_exchange_id_res res = { | 6627 | struct nfs41_exchange_id_res res = { |
6283 | 0 | 6628 | 0 |
@@ -7616,6 +7961,9 @@ nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle, | |||
7616 | break; | 7961 | break; |
7617 | } | 7962 | } |
7618 | 7963 | ||
7964 | if (!nfs_auth_info_match(&server->auth_info, flavor)) | ||
7965 | flavor = RPC_AUTH_MAXFLAVOR; | ||
7966 | |||
7619 | if (flavor != RPC_AUTH_MAXFLAVOR) { | 7967 | if (flavor != RPC_AUTH_MAXFLAVOR) { |
7620 | err = nfs4_lookup_root_sec(server, fhandle, | 7968 | err = nfs4_lookup_root_sec(server, fhandle, |
7621 | info, flavor); | 7969 | info, flavor); |
@@ -7887,6 +8235,18 @@ static const struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = { | |||
7887 | }; | 8235 | }; |
7888 | #endif | 8236 | #endif |
7889 | 8237 | ||
8238 | static const struct nfs4_mig_recovery_ops nfs40_mig_recovery_ops = { | ||
8239 | .get_locations = _nfs40_proc_get_locations, | ||
8240 | .fsid_present = _nfs40_proc_fsid_present, | ||
8241 | }; | ||
8242 | |||
8243 | #if defined(CONFIG_NFS_V4_1) | ||
8244 | static const struct nfs4_mig_recovery_ops nfs41_mig_recovery_ops = { | ||
8245 | .get_locations = _nfs41_proc_get_locations, | ||
8246 | .fsid_present = _nfs41_proc_fsid_present, | ||
8247 | }; | ||
8248 | #endif /* CONFIG_NFS_V4_1 */ | ||
8249 | |||
7890 | static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = { | 8250 | static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = { |
7891 | .minor_version = 0, | 8251 | .minor_version = 0, |
7892 | .init_caps = NFS_CAP_READDIRPLUS | 8252 | .init_caps = NFS_CAP_READDIRPLUS |
@@ -7902,6 +8262,7 @@ static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = { | |||
7902 | .reboot_recovery_ops = &nfs40_reboot_recovery_ops, | 8262 | .reboot_recovery_ops = &nfs40_reboot_recovery_ops, |
7903 | .nograce_recovery_ops = &nfs40_nograce_recovery_ops, | 8263 | .nograce_recovery_ops = &nfs40_nograce_recovery_ops, |
7904 | .state_renewal_ops = &nfs40_state_renewal_ops, | 8264 | .state_renewal_ops = &nfs40_state_renewal_ops, |
8265 | .mig_recovery_ops = &nfs40_mig_recovery_ops, | ||
7905 | }; | 8266 | }; |
7906 | 8267 | ||
7907 | #if defined(CONFIG_NFS_V4_1) | 8268 | #if defined(CONFIG_NFS_V4_1) |
@@ -7922,6 +8283,7 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = { | |||
7922 | .reboot_recovery_ops = &nfs41_reboot_recovery_ops, | 8283 | .reboot_recovery_ops = &nfs41_reboot_recovery_ops, |
7923 | .nograce_recovery_ops = &nfs41_nograce_recovery_ops, | 8284 | .nograce_recovery_ops = &nfs41_nograce_recovery_ops, |
7924 | .state_renewal_ops = &nfs41_state_renewal_ops, | 8285 | .state_renewal_ops = &nfs41_state_renewal_ops, |
8286 | .mig_recovery_ops = &nfs41_mig_recovery_ops, | ||
7925 | }; | 8287 | }; |
7926 | #endif | 8288 | #endif |
7927 | 8289 | ||
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index cc14cbb78b73..c8e729deb4f7 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -239,8 +239,6 @@ static void nfs4_end_drain_session(struct nfs_client *clp) | |||
239 | } | 239 | } |
240 | } | 240 | } |
241 | 241 | ||
242 | #if defined(CONFIG_NFS_V4_1) | ||
243 | |||
244 | static int nfs4_drain_slot_tbl(struct nfs4_slot_table *tbl) | 242 | static int nfs4_drain_slot_tbl(struct nfs4_slot_table *tbl) |
245 | { | 243 | { |
246 | set_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state); | 244 | set_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state); |
@@ -270,6 +268,8 @@ static int nfs4_begin_drain_session(struct nfs_client *clp) | |||
270 | return nfs4_drain_slot_tbl(&ses->fc_slot_table); | 268 | return nfs4_drain_slot_tbl(&ses->fc_slot_table); |
271 | } | 269 | } |
272 | 270 | ||
271 | #if defined(CONFIG_NFS_V4_1) | ||
272 | |||
273 | static int nfs41_setup_state_renewal(struct nfs_client *clp) | 273 | static int nfs41_setup_state_renewal(struct nfs_client *clp) |
274 | { | 274 | { |
275 | int status; | 275 | int status; |
@@ -1197,20 +1197,74 @@ void nfs4_schedule_lease_recovery(struct nfs_client *clp) | |||
1197 | } | 1197 | } |
1198 | EXPORT_SYMBOL_GPL(nfs4_schedule_lease_recovery); | 1198 | EXPORT_SYMBOL_GPL(nfs4_schedule_lease_recovery); |
1199 | 1199 | ||
1200 | /** | ||
1201 | * nfs4_schedule_migration_recovery - trigger migration recovery | ||
1202 | * | ||
1203 | * @server: FSID that is migrating | ||
1204 | * | ||
1205 | * Returns zero if recovery has started, otherwise a negative NFS4ERR | ||
1206 | * value is returned. | ||
1207 | */ | ||
1208 | int nfs4_schedule_migration_recovery(const struct nfs_server *server) | ||
1209 | { | ||
1210 | struct nfs_client *clp = server->nfs_client; | ||
1211 | |||
1212 | if (server->fh_expire_type != NFS4_FH_PERSISTENT) { | ||
1213 | pr_err("NFS: volatile file handles not supported (server %s)\n", | ||
1214 | clp->cl_hostname); | ||
1215 | return -NFS4ERR_IO; | ||
1216 | } | ||
1217 | |||
1218 | if (test_bit(NFS_MIG_FAILED, &server->mig_status)) | ||
1219 | return -NFS4ERR_IO; | ||
1220 | |||
1221 | dprintk("%s: scheduling migration recovery for (%llx:%llx) on %s\n", | ||
1222 | __func__, | ||
1223 | (unsigned long long)server->fsid.major, | ||
1224 | (unsigned long long)server->fsid.minor, | ||
1225 | clp->cl_hostname); | ||
1226 | |||
1227 | set_bit(NFS_MIG_IN_TRANSITION, | ||
1228 | &((struct nfs_server *)server)->mig_status); | ||
1229 | set_bit(NFS4CLNT_MOVED, &clp->cl_state); | ||
1230 | |||
1231 | nfs4_schedule_state_manager(clp); | ||
1232 | return 0; | ||
1233 | } | ||
1234 | EXPORT_SYMBOL_GPL(nfs4_schedule_migration_recovery); | ||
1235 | |||
1236 | /** | ||
1237 | * nfs4_schedule_lease_moved_recovery - start lease-moved recovery | ||
1238 | * | ||
1239 | * @clp: server to check for moved leases | ||
1240 | * | ||
1241 | */ | ||
1242 | void nfs4_schedule_lease_moved_recovery(struct nfs_client *clp) | ||
1243 | { | ||
1244 | dprintk("%s: scheduling lease-moved recovery for client ID %llx on %s\n", | ||
1245 | __func__, clp->cl_clientid, clp->cl_hostname); | ||
1246 | |||
1247 | set_bit(NFS4CLNT_LEASE_MOVED, &clp->cl_state); | ||
1248 | nfs4_schedule_state_manager(clp); | ||
1249 | } | ||
1250 | EXPORT_SYMBOL_GPL(nfs4_schedule_lease_moved_recovery); | ||
1251 | |||
1200 | int nfs4_wait_clnt_recover(struct nfs_client *clp) | 1252 | int nfs4_wait_clnt_recover(struct nfs_client *clp) |
1201 | { | 1253 | { |
1202 | int res; | 1254 | int res; |
1203 | 1255 | ||
1204 | might_sleep(); | 1256 | might_sleep(); |
1205 | 1257 | ||
1258 | atomic_inc(&clp->cl_count); | ||
1206 | res = wait_on_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING, | 1259 | res = wait_on_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING, |
1207 | nfs_wait_bit_killable, TASK_KILLABLE); | 1260 | nfs_wait_bit_killable, TASK_KILLABLE); |
1208 | if (res) | 1261 | if (res) |
1209 | return res; | 1262 | goto out; |
1210 | |||
1211 | if (clp->cl_cons_state < 0) | 1263 | if (clp->cl_cons_state < 0) |
1212 | return clp->cl_cons_state; | 1264 | res = clp->cl_cons_state; |
1213 | return 0; | 1265 | out: |
1266 | nfs_put_client(clp); | ||
1267 | return res; | ||
1214 | } | 1268 | } |
1215 | 1269 | ||
1216 | int nfs4_client_recover_expired_lease(struct nfs_client *clp) | 1270 | int nfs4_client_recover_expired_lease(struct nfs_client *clp) |
@@ -1375,8 +1429,8 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_ | |||
1375 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | 1429 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: |
1376 | goto out; | 1430 | goto out; |
1377 | default: | 1431 | default: |
1378 | printk(KERN_ERR "NFS: %s: unhandled error %d. " | 1432 | printk(KERN_ERR "NFS: %s: unhandled error %d\n", |
1379 | "Zeroing state\n", __func__, status); | 1433 | __func__, status); |
1380 | case -ENOMEM: | 1434 | case -ENOMEM: |
1381 | case -NFS4ERR_DENIED: | 1435 | case -NFS4ERR_DENIED: |
1382 | case -NFS4ERR_RECLAIM_BAD: | 1436 | case -NFS4ERR_RECLAIM_BAD: |
@@ -1422,7 +1476,7 @@ restart: | |||
1422 | if (status >= 0) { | 1476 | if (status >= 0) { |
1423 | status = nfs4_reclaim_locks(state, ops); | 1477 | status = nfs4_reclaim_locks(state, ops); |
1424 | if (status >= 0) { | 1478 | if (status >= 0) { |
1425 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) { | 1479 | if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) { |
1426 | spin_lock(&state->state_lock); | 1480 | spin_lock(&state->state_lock); |
1427 | list_for_each_entry(lock, &state->lock_states, ls_locks) { | 1481 | list_for_each_entry(lock, &state->lock_states, ls_locks) { |
1428 | if (!test_bit(NFS_LOCK_INITIALIZED, &lock->ls_flags)) | 1482 | if (!test_bit(NFS_LOCK_INITIALIZED, &lock->ls_flags)) |
@@ -1439,15 +1493,12 @@ restart: | |||
1439 | } | 1493 | } |
1440 | switch (status) { | 1494 | switch (status) { |
1441 | default: | 1495 | default: |
1442 | printk(KERN_ERR "NFS: %s: unhandled error %d. " | 1496 | printk(KERN_ERR "NFS: %s: unhandled error %d\n", |
1443 | "Zeroing state\n", __func__, status); | 1497 | __func__, status); |
1444 | case -ENOENT: | 1498 | case -ENOENT: |
1445 | case -ENOMEM: | 1499 | case -ENOMEM: |
1446 | case -ESTALE: | 1500 | case -ESTALE: |
1447 | /* | 1501 | /* Open state on this file cannot be recovered */ |
1448 | * Open state on this file cannot be recovered | ||
1449 | * All we can do is revert to using the zero stateid. | ||
1450 | */ | ||
1451 | nfs4_state_mark_recovery_failed(state, status); | 1502 | nfs4_state_mark_recovery_failed(state, status); |
1452 | break; | 1503 | break; |
1453 | case -EAGAIN: | 1504 | case -EAGAIN: |
@@ -1628,7 +1679,6 @@ static int nfs4_recovery_handle_error(struct nfs_client *clp, int error) | |||
1628 | nfs4_state_end_reclaim_reboot(clp); | 1679 | nfs4_state_end_reclaim_reboot(clp); |
1629 | break; | 1680 | break; |
1630 | case -NFS4ERR_STALE_CLIENTID: | 1681 | case -NFS4ERR_STALE_CLIENTID: |
1631 | case -NFS4ERR_LEASE_MOVED: | ||
1632 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 1682 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); |
1633 | nfs4_state_clear_reclaim_reboot(clp); | 1683 | nfs4_state_clear_reclaim_reboot(clp); |
1634 | nfs4_state_start_reclaim_reboot(clp); | 1684 | nfs4_state_start_reclaim_reboot(clp); |
@@ -1829,6 +1879,168 @@ static int nfs4_purge_lease(struct nfs_client *clp) | |||
1829 | return 0; | 1879 | return 0; |
1830 | } | 1880 | } |
1831 | 1881 | ||
1882 | /* | ||
1883 | * Try remote migration of one FSID from a source server to a | ||
1884 | * destination server. The source server provides a list of | ||
1885 | * potential destinations. | ||
1886 | * | ||
1887 | * Returns zero or a negative NFS4ERR status code. | ||
1888 | */ | ||
1889 | static int nfs4_try_migration(struct nfs_server *server, struct rpc_cred *cred) | ||
1890 | { | ||
1891 | struct nfs_client *clp = server->nfs_client; | ||
1892 | struct nfs4_fs_locations *locations = NULL; | ||
1893 | struct inode *inode; | ||
1894 | struct page *page; | ||
1895 | int status, result; | ||
1896 | |||
1897 | dprintk("--> %s: FSID %llx:%llx on \"%s\"\n", __func__, | ||
1898 | (unsigned long long)server->fsid.major, | ||
1899 | (unsigned long long)server->fsid.minor, | ||
1900 | clp->cl_hostname); | ||
1901 | |||
1902 | result = 0; | ||
1903 | page = alloc_page(GFP_KERNEL); | ||
1904 | locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL); | ||
1905 | if (page == NULL || locations == NULL) { | ||
1906 | dprintk("<-- %s: no memory\n", __func__); | ||
1907 | goto out; | ||
1908 | } | ||
1909 | |||
1910 | inode = server->super->s_root->d_inode; | ||
1911 | result = nfs4_proc_get_locations(inode, locations, page, cred); | ||
1912 | if (result) { | ||
1913 | dprintk("<-- %s: failed to retrieve fs_locations: %d\n", | ||
1914 | __func__, result); | ||
1915 | goto out; | ||
1916 | } | ||
1917 | |||
1918 | result = -NFS4ERR_NXIO; | ||
1919 | if (!(locations->fattr.valid & NFS_ATTR_FATTR_V4_LOCATIONS)) { | ||
1920 | dprintk("<-- %s: No fs_locations data, migration skipped\n", | ||
1921 | __func__); | ||
1922 | goto out; | ||
1923 | } | ||
1924 | |||
1925 | nfs4_begin_drain_session(clp); | ||
1926 | |||
1927 | status = nfs4_replace_transport(server, locations); | ||
1928 | if (status != 0) { | ||
1929 | dprintk("<-- %s: failed to replace transport: %d\n", | ||
1930 | __func__, status); | ||
1931 | goto out; | ||
1932 | } | ||
1933 | |||
1934 | result = 0; | ||
1935 | dprintk("<-- %s: migration succeeded\n", __func__); | ||
1936 | |||
1937 | out: | ||
1938 | if (page != NULL) | ||
1939 | __free_page(page); | ||
1940 | kfree(locations); | ||
1941 | if (result) { | ||
1942 | pr_err("NFS: migration recovery failed (server %s)\n", | ||
1943 | clp->cl_hostname); | ||
1944 | set_bit(NFS_MIG_FAILED, &server->mig_status); | ||
1945 | } | ||
1946 | return result; | ||
1947 | } | ||
1948 | |||
1949 | /* | ||
1950 | * Returns zero or a negative NFS4ERR status code. | ||
1951 | */ | ||
1952 | static int nfs4_handle_migration(struct nfs_client *clp) | ||
1953 | { | ||
1954 | const struct nfs4_state_maintenance_ops *ops = | ||
1955 | clp->cl_mvops->state_renewal_ops; | ||
1956 | struct nfs_server *server; | ||
1957 | struct rpc_cred *cred; | ||
1958 | |||
1959 | dprintk("%s: migration reported on \"%s\"\n", __func__, | ||
1960 | clp->cl_hostname); | ||
1961 | |||
1962 | spin_lock(&clp->cl_lock); | ||
1963 | cred = ops->get_state_renewal_cred_locked(clp); | ||
1964 | spin_unlock(&clp->cl_lock); | ||
1965 | if (cred == NULL) | ||
1966 | return -NFS4ERR_NOENT; | ||
1967 | |||
1968 | clp->cl_mig_gen++; | ||
1969 | restart: | ||
1970 | rcu_read_lock(); | ||
1971 | list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { | ||
1972 | int status; | ||
1973 | |||
1974 | if (server->mig_gen == clp->cl_mig_gen) | ||
1975 | continue; | ||
1976 | server->mig_gen = clp->cl_mig_gen; | ||
1977 | |||
1978 | if (!test_and_clear_bit(NFS_MIG_IN_TRANSITION, | ||
1979 | &server->mig_status)) | ||
1980 | continue; | ||
1981 | |||
1982 | rcu_read_unlock(); | ||
1983 | status = nfs4_try_migration(server, cred); | ||
1984 | if (status < 0) { | ||
1985 | put_rpccred(cred); | ||
1986 | return status; | ||
1987 | } | ||
1988 | goto restart; | ||
1989 | } | ||
1990 | rcu_read_unlock(); | ||
1991 | put_rpccred(cred); | ||
1992 | return 0; | ||
1993 | } | ||
1994 | |||
1995 | /* | ||
1996 | * Test each nfs_server on the clp's cl_superblocks list to see | ||
1997 | * if it's moved to another server. Stop when the server no longer | ||
1998 | * returns NFS4ERR_LEASE_MOVED. | ||
1999 | */ | ||
2000 | static int nfs4_handle_lease_moved(struct nfs_client *clp) | ||
2001 | { | ||
2002 | const struct nfs4_state_maintenance_ops *ops = | ||
2003 | clp->cl_mvops->state_renewal_ops; | ||
2004 | struct nfs_server *server; | ||
2005 | struct rpc_cred *cred; | ||
2006 | |||
2007 | dprintk("%s: lease moved reported on \"%s\"\n", __func__, | ||
2008 | clp->cl_hostname); | ||
2009 | |||
2010 | spin_lock(&clp->cl_lock); | ||
2011 | cred = ops->get_state_renewal_cred_locked(clp); | ||
2012 | spin_unlock(&clp->cl_lock); | ||
2013 | if (cred == NULL) | ||
2014 | return -NFS4ERR_NOENT; | ||
2015 | |||
2016 | clp->cl_mig_gen++; | ||
2017 | restart: | ||
2018 | rcu_read_lock(); | ||
2019 | list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { | ||
2020 | struct inode *inode; | ||
2021 | int status; | ||
2022 | |||
2023 | if (server->mig_gen == clp->cl_mig_gen) | ||
2024 | continue; | ||
2025 | server->mig_gen = clp->cl_mig_gen; | ||
2026 | |||
2027 | rcu_read_unlock(); | ||
2028 | |||
2029 | inode = server->super->s_root->d_inode; | ||
2030 | status = nfs4_proc_fsid_present(inode, cred); | ||
2031 | if (status != -NFS4ERR_MOVED) | ||
2032 | goto restart; /* wasn't this one */ | ||
2033 | if (nfs4_try_migration(server, cred) == -NFS4ERR_LEASE_MOVED) | ||
2034 | goto restart; /* there are more */ | ||
2035 | goto out; | ||
2036 | } | ||
2037 | rcu_read_unlock(); | ||
2038 | |||
2039 | out: | ||
2040 | put_rpccred(cred); | ||
2041 | return 0; | ||
2042 | } | ||
2043 | |||
1832 | /** | 2044 | /** |
1833 | * nfs4_discover_server_trunking - Detect server IP address trunking | 2045 | * nfs4_discover_server_trunking - Detect server IP address trunking |
1834 | * | 2046 | * |
@@ -2017,9 +2229,10 @@ void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags) | |||
2017 | nfs41_handle_server_reboot(clp); | 2229 | nfs41_handle_server_reboot(clp); |
2018 | if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED | | 2230 | if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED | |
2019 | SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED | | 2231 | SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED | |
2020 | SEQ4_STATUS_ADMIN_STATE_REVOKED | | 2232 | SEQ4_STATUS_ADMIN_STATE_REVOKED)) |
2021 | SEQ4_STATUS_LEASE_MOVED)) | ||
2022 | nfs41_handle_state_revoked(clp); | 2233 | nfs41_handle_state_revoked(clp); |
2234 | if (flags & SEQ4_STATUS_LEASE_MOVED) | ||
2235 | nfs4_schedule_lease_moved_recovery(clp); | ||
2023 | if (flags & SEQ4_STATUS_RECALLABLE_STATE_REVOKED) | 2236 | if (flags & SEQ4_STATUS_RECALLABLE_STATE_REVOKED) |
2024 | nfs41_handle_recallable_state_revoked(clp); | 2237 | nfs41_handle_recallable_state_revoked(clp); |
2025 | if (flags & SEQ4_STATUS_BACKCHANNEL_FAULT) | 2238 | if (flags & SEQ4_STATUS_BACKCHANNEL_FAULT) |
@@ -2157,7 +2370,20 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
2157 | status = nfs4_check_lease(clp); | 2370 | status = nfs4_check_lease(clp); |
2158 | if (status < 0) | 2371 | if (status < 0) |
2159 | goto out_error; | 2372 | goto out_error; |
2160 | continue; | 2373 | } |
2374 | |||
2375 | if (test_and_clear_bit(NFS4CLNT_MOVED, &clp->cl_state)) { | ||
2376 | section = "migration"; | ||
2377 | status = nfs4_handle_migration(clp); | ||
2378 | if (status < 0) | ||
2379 | goto out_error; | ||
2380 | } | ||
2381 | |||
2382 | if (test_and_clear_bit(NFS4CLNT_LEASE_MOVED, &clp->cl_state)) { | ||
2383 | section = "lease moved"; | ||
2384 | status = nfs4_handle_lease_moved(clp); | ||
2385 | if (status < 0) | ||
2386 | goto out_error; | ||
2161 | } | 2387 | } |
2162 | 2388 | ||
2163 | /* First recover reboot state... */ | 2389 | /* First recover reboot state... */ |
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c index e26acdd1a645..65ab0a0ca1c4 100644 --- a/fs/nfs/nfs4super.c +++ b/fs/nfs/nfs4super.c | |||
@@ -261,9 +261,9 @@ struct dentry *nfs4_try_mount(int flags, const char *dev_name, | |||
261 | 261 | ||
262 | res = nfs_follow_remote_path(root_mnt, export_path); | 262 | res = nfs_follow_remote_path(root_mnt, export_path); |
263 | 263 | ||
264 | dfprintk(MOUNT, "<-- nfs4_try_mount() = %ld%s\n", | 264 | dfprintk(MOUNT, "<-- nfs4_try_mount() = %d%s\n", |
265 | IS_ERR(res) ? PTR_ERR(res) : 0, | 265 | PTR_ERR_OR_ZERO(res), |
266 | IS_ERR(res) ? " [error]" : ""); | 266 | IS_ERR(res) ? " [error]" : ""); |
267 | return res; | 267 | return res; |
268 | } | 268 | } |
269 | 269 | ||
@@ -319,9 +319,9 @@ static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type, | |||
319 | data->mnt_path = export_path; | 319 | data->mnt_path = export_path; |
320 | 320 | ||
321 | res = nfs_follow_remote_path(root_mnt, export_path); | 321 | res = nfs_follow_remote_path(root_mnt, export_path); |
322 | dprintk("<-- nfs4_referral_mount() = %ld%s\n", | 322 | dprintk("<-- nfs4_referral_mount() = %d%s\n", |
323 | IS_ERR(res) ? PTR_ERR(res) : 0, | 323 | PTR_ERR_OR_ZERO(res), |
324 | IS_ERR(res) ? " [error]" : ""); | 324 | IS_ERR(res) ? " [error]" : ""); |
325 | return res; | 325 | return res; |
326 | } | 326 | } |
327 | 327 | ||
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 79210d23f607..5be2868c02f1 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -105,12 +105,8 @@ static int nfs4_stat_to_errno(int); | |||
105 | #ifdef CONFIG_NFS_V4_SECURITY_LABEL | 105 | #ifdef CONFIG_NFS_V4_SECURITY_LABEL |
106 | /* PI(4 bytes) + LFS(4 bytes) + 1(for null terminator?) + MAXLABELLEN */ | 106 | /* PI(4 bytes) + LFS(4 bytes) + 1(for null terminator?) + MAXLABELLEN */ |
107 | #define nfs4_label_maxsz (4 + 4 + 1 + XDR_QUADLEN(NFS4_MAXLABELLEN)) | 107 | #define nfs4_label_maxsz (4 + 4 + 1 + XDR_QUADLEN(NFS4_MAXLABELLEN)) |
108 | #define encode_readdir_space 24 | ||
109 | #define encode_readdir_bitmask_sz 3 | ||
110 | #else | 108 | #else |
111 | #define nfs4_label_maxsz 0 | 109 | #define nfs4_label_maxsz 0 |
112 | #define encode_readdir_space 20 | ||
113 | #define encode_readdir_bitmask_sz 2 | ||
114 | #endif | 110 | #endif |
115 | /* We support only one layout type per file system */ | 111 | /* We support only one layout type per file system */ |
116 | #define decode_mdsthreshold_maxsz (1 + 1 + nfs4_fattr_bitmap_maxsz + 1 + 8) | 112 | #define decode_mdsthreshold_maxsz (1 + 1 + nfs4_fattr_bitmap_maxsz + 1 + 8) |
@@ -595,11 +591,13 @@ static int nfs4_stat_to_errno(int); | |||
595 | #define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \ | 591 | #define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \ |
596 | encode_sequence_maxsz + \ | 592 | encode_sequence_maxsz + \ |
597 | encode_putfh_maxsz + \ | 593 | encode_putfh_maxsz + \ |
598 | encode_getattr_maxsz) | 594 | encode_getattr_maxsz + \ |
595 | encode_renew_maxsz) | ||
599 | #define NFS4_dec_getattr_sz (compound_decode_hdr_maxsz + \ | 596 | #define NFS4_dec_getattr_sz (compound_decode_hdr_maxsz + \ |
600 | decode_sequence_maxsz + \ | 597 | decode_sequence_maxsz + \ |
601 | decode_putfh_maxsz + \ | 598 | decode_putfh_maxsz + \ |
602 | decode_getattr_maxsz) | 599 | decode_getattr_maxsz + \ |
600 | decode_renew_maxsz) | ||
603 | #define NFS4_enc_lookup_sz (compound_encode_hdr_maxsz + \ | 601 | #define NFS4_enc_lookup_sz (compound_encode_hdr_maxsz + \ |
604 | encode_sequence_maxsz + \ | 602 | encode_sequence_maxsz + \ |
605 | encode_putfh_maxsz + \ | 603 | encode_putfh_maxsz + \ |
@@ -736,13 +734,15 @@ static int nfs4_stat_to_errno(int); | |||
736 | encode_sequence_maxsz + \ | 734 | encode_sequence_maxsz + \ |
737 | encode_putfh_maxsz + \ | 735 | encode_putfh_maxsz + \ |
738 | encode_lookup_maxsz + \ | 736 | encode_lookup_maxsz + \ |
739 | encode_fs_locations_maxsz) | 737 | encode_fs_locations_maxsz + \ |
738 | encode_renew_maxsz) | ||
740 | #define NFS4_dec_fs_locations_sz \ | 739 | #define NFS4_dec_fs_locations_sz \ |
741 | (compound_decode_hdr_maxsz + \ | 740 | (compound_decode_hdr_maxsz + \ |
742 | decode_sequence_maxsz + \ | 741 | decode_sequence_maxsz + \ |
743 | decode_putfh_maxsz + \ | 742 | decode_putfh_maxsz + \ |
744 | decode_lookup_maxsz + \ | 743 | decode_lookup_maxsz + \ |
745 | decode_fs_locations_maxsz) | 744 | decode_fs_locations_maxsz + \ |
745 | decode_renew_maxsz) | ||
746 | #define NFS4_enc_secinfo_sz (compound_encode_hdr_maxsz + \ | 746 | #define NFS4_enc_secinfo_sz (compound_encode_hdr_maxsz + \ |
747 | encode_sequence_maxsz + \ | 747 | encode_sequence_maxsz + \ |
748 | encode_putfh_maxsz + \ | 748 | encode_putfh_maxsz + \ |
@@ -751,6 +751,18 @@ static int nfs4_stat_to_errno(int); | |||
751 | decode_sequence_maxsz + \ | 751 | decode_sequence_maxsz + \ |
752 | decode_putfh_maxsz + \ | 752 | decode_putfh_maxsz + \ |
753 | decode_secinfo_maxsz) | 753 | decode_secinfo_maxsz) |
754 | #define NFS4_enc_fsid_present_sz \ | ||
755 | (compound_encode_hdr_maxsz + \ | ||
756 | encode_sequence_maxsz + \ | ||
757 | encode_putfh_maxsz + \ | ||
758 | encode_getfh_maxsz + \ | ||
759 | encode_renew_maxsz) | ||
760 | #define NFS4_dec_fsid_present_sz \ | ||
761 | (compound_decode_hdr_maxsz + \ | ||
762 | decode_sequence_maxsz + \ | ||
763 | decode_putfh_maxsz + \ | ||
764 | decode_getfh_maxsz + \ | ||
765 | decode_renew_maxsz) | ||
754 | #if defined(CONFIG_NFS_V4_1) | 766 | #if defined(CONFIG_NFS_V4_1) |
755 | #define NFS4_enc_bind_conn_to_session_sz \ | 767 | #define NFS4_enc_bind_conn_to_session_sz \ |
756 | (compound_encode_hdr_maxsz + \ | 768 | (compound_encode_hdr_maxsz + \ |
@@ -1565,6 +1577,8 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg | |||
1565 | }; | 1577 | }; |
1566 | uint32_t dircount = readdir->count >> 1; | 1578 | uint32_t dircount = readdir->count >> 1; |
1567 | __be32 *p, verf[2]; | 1579 | __be32 *p, verf[2]; |
1580 | uint32_t attrlen = 0; | ||
1581 | unsigned int i; | ||
1568 | 1582 | ||
1569 | if (readdir->plus) { | 1583 | if (readdir->plus) { |
1570 | attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE| | 1584 | attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE| |
@@ -1573,26 +1587,27 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg | |||
1573 | FATTR4_WORD1_OWNER_GROUP|FATTR4_WORD1_RAWDEV| | 1587 | FATTR4_WORD1_OWNER_GROUP|FATTR4_WORD1_RAWDEV| |
1574 | FATTR4_WORD1_SPACE_USED|FATTR4_WORD1_TIME_ACCESS| | 1588 | FATTR4_WORD1_SPACE_USED|FATTR4_WORD1_TIME_ACCESS| |
1575 | FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; | 1589 | FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; |
1590 | attrs[2] |= FATTR4_WORD2_SECURITY_LABEL; | ||
1576 | dircount >>= 1; | 1591 | dircount >>= 1; |
1577 | } | 1592 | } |
1578 | /* Use mounted_on_fileid only if the server supports it */ | 1593 | /* Use mounted_on_fileid only if the server supports it */ |
1579 | if (!(readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)) | 1594 | if (!(readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)) |
1580 | attrs[0] |= FATTR4_WORD0_FILEID; | 1595 | attrs[0] |= FATTR4_WORD0_FILEID; |
1596 | for (i = 0; i < ARRAY_SIZE(attrs); i++) { | ||
1597 | attrs[i] &= readdir->bitmask[i]; | ||
1598 | if (attrs[i] != 0) | ||
1599 | attrlen = i+1; | ||
1600 | } | ||
1581 | 1601 | ||
1582 | encode_op_hdr(xdr, OP_READDIR, decode_readdir_maxsz, hdr); | 1602 | encode_op_hdr(xdr, OP_READDIR, decode_readdir_maxsz, hdr); |
1583 | encode_uint64(xdr, readdir->cookie); | 1603 | encode_uint64(xdr, readdir->cookie); |
1584 | encode_nfs4_verifier(xdr, &readdir->verifier); | 1604 | encode_nfs4_verifier(xdr, &readdir->verifier); |
1585 | p = reserve_space(xdr, encode_readdir_space); | 1605 | p = reserve_space(xdr, 12 + (attrlen << 2)); |
1586 | *p++ = cpu_to_be32(dircount); | 1606 | *p++ = cpu_to_be32(dircount); |
1587 | *p++ = cpu_to_be32(readdir->count); | 1607 | *p++ = cpu_to_be32(readdir->count); |
1588 | *p++ = cpu_to_be32(encode_readdir_bitmask_sz); | 1608 | *p++ = cpu_to_be32(attrlen); |
1589 | *p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]); | 1609 | for (i = 0; i < attrlen; i++) |
1590 | *p = cpu_to_be32(attrs[1] & readdir->bitmask[1]); | 1610 | *p++ = cpu_to_be32(attrs[i]); |
1591 | if (encode_readdir_bitmask_sz > 2) { | ||
1592 | if (hdr->minorversion > 1) | ||
1593 | attrs[2] |= FATTR4_WORD2_SECURITY_LABEL; | ||
1594 | p++, *p++ = cpu_to_be32(attrs[2] & readdir->bitmask[2]); | ||
1595 | } | ||
1596 | memcpy(verf, readdir->verifier.data, sizeof(verf)); | 1611 | memcpy(verf, readdir->verifier.data, sizeof(verf)); |
1597 | 1612 | ||
1598 | dprintk("%s: cookie = %llu, verifier = %08x:%08x, bitmap = %08x:%08x:%08x\n", | 1613 | dprintk("%s: cookie = %llu, verifier = %08x:%08x, bitmap = %08x:%08x:%08x\n", |
@@ -2687,11 +2702,20 @@ static void nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, | |||
2687 | 2702 | ||
2688 | encode_compound_hdr(xdr, req, &hdr); | 2703 | encode_compound_hdr(xdr, req, &hdr); |
2689 | encode_sequence(xdr, &args->seq_args, &hdr); | 2704 | encode_sequence(xdr, &args->seq_args, &hdr); |
2690 | encode_putfh(xdr, args->dir_fh, &hdr); | 2705 | if (args->migration) { |
2691 | encode_lookup(xdr, args->name, &hdr); | 2706 | encode_putfh(xdr, args->fh, &hdr); |
2692 | replen = hdr.replen; /* get the attribute into args->page */ | 2707 | replen = hdr.replen; |
2693 | encode_fs_locations(xdr, args->bitmask, &hdr); | 2708 | encode_fs_locations(xdr, args->bitmask, &hdr); |
2709 | if (args->renew) | ||
2710 | encode_renew(xdr, args->clientid, &hdr); | ||
2711 | } else { | ||
2712 | encode_putfh(xdr, args->dir_fh, &hdr); | ||
2713 | encode_lookup(xdr, args->name, &hdr); | ||
2714 | replen = hdr.replen; | ||
2715 | encode_fs_locations(xdr, args->bitmask, &hdr); | ||
2716 | } | ||
2694 | 2717 | ||
2718 | /* Set up reply kvec to capture returned fs_locations array. */ | ||
2695 | xdr_inline_pages(&req->rq_rcv_buf, replen << 2, &args->page, | 2719 | xdr_inline_pages(&req->rq_rcv_buf, replen << 2, &args->page, |
2696 | 0, PAGE_SIZE); | 2720 | 0, PAGE_SIZE); |
2697 | encode_nops(&hdr); | 2721 | encode_nops(&hdr); |
@@ -2715,6 +2739,26 @@ static void nfs4_xdr_enc_secinfo(struct rpc_rqst *req, | |||
2715 | encode_nops(&hdr); | 2739 | encode_nops(&hdr); |
2716 | } | 2740 | } |
2717 | 2741 | ||
2742 | /* | ||
2743 | * Encode FSID_PRESENT request | ||
2744 | */ | ||
2745 | static void nfs4_xdr_enc_fsid_present(struct rpc_rqst *req, | ||
2746 | struct xdr_stream *xdr, | ||
2747 | struct nfs4_fsid_present_arg *args) | ||
2748 | { | ||
2749 | struct compound_hdr hdr = { | ||
2750 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), | ||
2751 | }; | ||
2752 | |||
2753 | encode_compound_hdr(xdr, req, &hdr); | ||
2754 | encode_sequence(xdr, &args->seq_args, &hdr); | ||
2755 | encode_putfh(xdr, args->fh, &hdr); | ||
2756 | encode_getfh(xdr, &hdr); | ||
2757 | if (args->renew) | ||
2758 | encode_renew(xdr, args->clientid, &hdr); | ||
2759 | encode_nops(&hdr); | ||
2760 | } | ||
2761 | |||
2718 | #if defined(CONFIG_NFS_V4_1) | 2762 | #if defined(CONFIG_NFS_V4_1) |
2719 | /* | 2763 | /* |
2720 | * BIND_CONN_TO_SESSION request | 2764 | * BIND_CONN_TO_SESSION request |
@@ -6824,13 +6868,26 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, | |||
6824 | status = decode_putfh(xdr); | 6868 | status = decode_putfh(xdr); |
6825 | if (status) | 6869 | if (status) |
6826 | goto out; | 6870 | goto out; |
6827 | status = decode_lookup(xdr); | 6871 | if (res->migration) { |
6828 | if (status) | 6872 | xdr_enter_page(xdr, PAGE_SIZE); |
6829 | goto out; | 6873 | status = decode_getfattr_generic(xdr, |
6830 | xdr_enter_page(xdr, PAGE_SIZE); | 6874 | &res->fs_locations->fattr, |
6831 | status = decode_getfattr_generic(xdr, &res->fs_locations->fattr, | 6875 | NULL, res->fs_locations, |
6876 | NULL, res->fs_locations->server); | ||
6877 | if (status) | ||
6878 | goto out; | ||
6879 | if (res->renew) | ||
6880 | status = decode_renew(xdr); | ||
6881 | } else { | ||
6882 | status = decode_lookup(xdr); | ||
6883 | if (status) | ||
6884 | goto out; | ||
6885 | xdr_enter_page(xdr, PAGE_SIZE); | ||
6886 | status = decode_getfattr_generic(xdr, | ||
6887 | &res->fs_locations->fattr, | ||
6832 | NULL, res->fs_locations, | 6888 | NULL, res->fs_locations, |
6833 | NULL, res->fs_locations->server); | 6889 | NULL, res->fs_locations->server); |
6890 | } | ||
6834 | out: | 6891 | out: |
6835 | return status; | 6892 | return status; |
6836 | } | 6893 | } |
@@ -6859,6 +6916,34 @@ out: | |||
6859 | return status; | 6916 | return status; |
6860 | } | 6917 | } |
6861 | 6918 | ||
6919 | /* | ||
6920 | * Decode FSID_PRESENT response | ||
6921 | */ | ||
6922 | static int nfs4_xdr_dec_fsid_present(struct rpc_rqst *rqstp, | ||
6923 | struct xdr_stream *xdr, | ||
6924 | struct nfs4_fsid_present_res *res) | ||
6925 | { | ||
6926 | struct compound_hdr hdr; | ||
6927 | int status; | ||
6928 | |||
6929 | status = decode_compound_hdr(xdr, &hdr); | ||
6930 | if (status) | ||
6931 | goto out; | ||
6932 | status = decode_sequence(xdr, &res->seq_res, rqstp); | ||
6933 | if (status) | ||
6934 | goto out; | ||
6935 | status = decode_putfh(xdr); | ||
6936 | if (status) | ||
6937 | goto out; | ||
6938 | status = decode_getfh(xdr, res->fh); | ||
6939 | if (status) | ||
6940 | goto out; | ||
6941 | if (res->renew) | ||
6942 | status = decode_renew(xdr); | ||
6943 | out: | ||
6944 | return status; | ||
6945 | } | ||
6946 | |||
6862 | #if defined(CONFIG_NFS_V4_1) | 6947 | #if defined(CONFIG_NFS_V4_1) |
6863 | /* | 6948 | /* |
6864 | * Decode BIND_CONN_TO_SESSION response | 6949 | * Decode BIND_CONN_TO_SESSION response |
@@ -7373,6 +7458,7 @@ struct rpc_procinfo nfs4_procedures[] = { | |||
7373 | PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations), | 7458 | PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations), |
7374 | PROC(RELEASE_LOCKOWNER, enc_release_lockowner, dec_release_lockowner), | 7459 | PROC(RELEASE_LOCKOWNER, enc_release_lockowner, dec_release_lockowner), |
7375 | PROC(SECINFO, enc_secinfo, dec_secinfo), | 7460 | PROC(SECINFO, enc_secinfo, dec_secinfo), |
7461 | PROC(FSID_PRESENT, enc_fsid_present, dec_fsid_present), | ||
7376 | #if defined(CONFIG_NFS_V4_1) | 7462 | #if defined(CONFIG_NFS_V4_1) |
7377 | PROC(EXCHANGE_ID, enc_exchange_id, dec_exchange_id), | 7463 | PROC(EXCHANGE_ID, enc_exchange_id, dec_exchange_id), |
7378 | PROC(CREATE_SESSION, enc_create_session, dec_create_session), | 7464 | PROC(CREATE_SESSION, enc_create_session, dec_create_session), |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index a03b9c6f9489..317d6fc2160e 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -497,7 +497,8 @@ static const char *nfs_pseudoflavour_to_name(rpc_authflavor_t flavour) | |||
497 | static const struct { | 497 | static const struct { |
498 | rpc_authflavor_t flavour; | 498 | rpc_authflavor_t flavour; |
499 | const char *str; | 499 | const char *str; |
500 | } sec_flavours[] = { | 500 | } sec_flavours[NFS_AUTH_INFO_MAX_FLAVORS] = { |
501 | /* update NFS_AUTH_INFO_MAX_FLAVORS when this list changes! */ | ||
501 | { RPC_AUTH_NULL, "null" }, | 502 | { RPC_AUTH_NULL, "null" }, |
502 | { RPC_AUTH_UNIX, "sys" }, | 503 | { RPC_AUTH_UNIX, "sys" }, |
503 | { RPC_AUTH_GSS_KRB5, "krb5" }, | 504 | { RPC_AUTH_GSS_KRB5, "krb5" }, |
@@ -923,8 +924,7 @@ static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(void) | |||
923 | data->mount_server.port = NFS_UNSPEC_PORT; | 924 | data->mount_server.port = NFS_UNSPEC_PORT; |
924 | data->nfs_server.port = NFS_UNSPEC_PORT; | 925 | data->nfs_server.port = NFS_UNSPEC_PORT; |
925 | data->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 926 | data->nfs_server.protocol = XPRT_TRANSPORT_TCP; |
926 | data->auth_flavors[0] = RPC_AUTH_MAXFLAVOR; | 927 | data->selected_flavor = RPC_AUTH_MAXFLAVOR; |
927 | data->auth_flavor_len = 0; | ||
928 | data->minorversion = 0; | 928 | data->minorversion = 0; |
929 | data->need_mount = true; | 929 | data->need_mount = true; |
930 | data->net = current->nsproxy->net_ns; | 930 | data->net = current->nsproxy->net_ns; |
@@ -1019,12 +1019,51 @@ static void nfs_set_mount_transport_protocol(struct nfs_parsed_mount_data *mnt) | |||
1019 | } | 1019 | } |
1020 | } | 1020 | } |
1021 | 1021 | ||
1022 | static void nfs_set_auth_parsed_mount_data(struct nfs_parsed_mount_data *data, | 1022 | /* |
1023 | rpc_authflavor_t pseudoflavor) | 1023 | * Add 'flavor' to 'auth_info' if not already present. |
1024 | * Returns true if 'flavor' ends up in the list, false otherwise | ||
1025 | */ | ||
1026 | static bool nfs_auth_info_add(struct nfs_auth_info *auth_info, | ||
1027 | rpc_authflavor_t flavor) | ||
1028 | { | ||
1029 | unsigned int i; | ||
1030 | unsigned int max_flavor_len = (sizeof(auth_info->flavors) / | ||
1031 | sizeof(auth_info->flavors[0])); | ||
1032 | |||
1033 | /* make sure this flavor isn't already in the list */ | ||
1034 | for (i = 0; i < auth_info->flavor_len; i++) { | ||
1035 | if (flavor == auth_info->flavors[i]) | ||
1036 | return true; | ||
1037 | } | ||
1038 | |||
1039 | if (auth_info->flavor_len + 1 >= max_flavor_len) { | ||
1040 | dfprintk(MOUNT, "NFS: too many sec= flavors\n"); | ||
1041 | return false; | ||
1042 | } | ||
1043 | |||
1044 | auth_info->flavors[auth_info->flavor_len++] = flavor; | ||
1045 | return true; | ||
1046 | } | ||
1047 | |||
1048 | /* | ||
1049 | * Return true if 'match' is in auth_info or auth_info is empty. | ||
1050 | * Return false otherwise. | ||
1051 | */ | ||
1052 | bool nfs_auth_info_match(const struct nfs_auth_info *auth_info, | ||
1053 | rpc_authflavor_t match) | ||
1024 | { | 1054 | { |
1025 | data->auth_flavors[0] = pseudoflavor; | 1055 | int i; |
1026 | data->auth_flavor_len = 1; | 1056 | |
1057 | if (!auth_info->flavor_len) | ||
1058 | return true; | ||
1059 | |||
1060 | for (i = 0; i < auth_info->flavor_len; i++) { | ||
1061 | if (auth_info->flavors[i] == match) | ||
1062 | return true; | ||
1063 | } | ||
1064 | return false; | ||
1027 | } | 1065 | } |
1066 | EXPORT_SYMBOL_GPL(nfs_auth_info_match); | ||
1028 | 1067 | ||
1029 | /* | 1068 | /* |
1030 | * Parse the value of the 'sec=' option. | 1069 | * Parse the value of the 'sec=' option. |
@@ -1034,49 +1073,55 @@ static int nfs_parse_security_flavors(char *value, | |||
1034 | { | 1073 | { |
1035 | substring_t args[MAX_OPT_ARGS]; | 1074 | substring_t args[MAX_OPT_ARGS]; |
1036 | rpc_authflavor_t pseudoflavor; | 1075 | rpc_authflavor_t pseudoflavor; |
1076 | char *p; | ||
1037 | 1077 | ||
1038 | dfprintk(MOUNT, "NFS: parsing sec=%s option\n", value); | 1078 | dfprintk(MOUNT, "NFS: parsing sec=%s option\n", value); |
1039 | 1079 | ||
1040 | switch (match_token(value, nfs_secflavor_tokens, args)) { | 1080 | while ((p = strsep(&value, ":")) != NULL) { |
1041 | case Opt_sec_none: | 1081 | switch (match_token(p, nfs_secflavor_tokens, args)) { |
1042 | pseudoflavor = RPC_AUTH_NULL; | 1082 | case Opt_sec_none: |
1043 | break; | 1083 | pseudoflavor = RPC_AUTH_NULL; |
1044 | case Opt_sec_sys: | 1084 | break; |
1045 | pseudoflavor = RPC_AUTH_UNIX; | 1085 | case Opt_sec_sys: |
1046 | break; | 1086 | pseudoflavor = RPC_AUTH_UNIX; |
1047 | case Opt_sec_krb5: | 1087 | break; |
1048 | pseudoflavor = RPC_AUTH_GSS_KRB5; | 1088 | case Opt_sec_krb5: |
1049 | break; | 1089 | pseudoflavor = RPC_AUTH_GSS_KRB5; |
1050 | case Opt_sec_krb5i: | 1090 | break; |
1051 | pseudoflavor = RPC_AUTH_GSS_KRB5I; | 1091 | case Opt_sec_krb5i: |
1052 | break; | 1092 | pseudoflavor = RPC_AUTH_GSS_KRB5I; |
1053 | case Opt_sec_krb5p: | 1093 | break; |
1054 | pseudoflavor = RPC_AUTH_GSS_KRB5P; | 1094 | case Opt_sec_krb5p: |
1055 | break; | 1095 | pseudoflavor = RPC_AUTH_GSS_KRB5P; |
1056 | case Opt_sec_lkey: | 1096 | break; |
1057 | pseudoflavor = RPC_AUTH_GSS_LKEY; | 1097 | case Opt_sec_lkey: |
1058 | break; | 1098 | pseudoflavor = RPC_AUTH_GSS_LKEY; |
1059 | case Opt_sec_lkeyi: | 1099 | break; |
1060 | pseudoflavor = RPC_AUTH_GSS_LKEYI; | 1100 | case Opt_sec_lkeyi: |
1061 | break; | 1101 | pseudoflavor = RPC_AUTH_GSS_LKEYI; |
1062 | case Opt_sec_lkeyp: | 1102 | break; |
1063 | pseudoflavor = RPC_AUTH_GSS_LKEYP; | 1103 | case Opt_sec_lkeyp: |
1064 | break; | 1104 | pseudoflavor = RPC_AUTH_GSS_LKEYP; |
1065 | case Opt_sec_spkm: | 1105 | break; |
1066 | pseudoflavor = RPC_AUTH_GSS_SPKM; | 1106 | case Opt_sec_spkm: |
1067 | break; | 1107 | pseudoflavor = RPC_AUTH_GSS_SPKM; |
1068 | case Opt_sec_spkmi: | 1108 | break; |
1069 | pseudoflavor = RPC_AUTH_GSS_SPKMI; | 1109 | case Opt_sec_spkmi: |
1070 | break; | 1110 | pseudoflavor = RPC_AUTH_GSS_SPKMI; |
1071 | case Opt_sec_spkmp: | 1111 | break; |
1072 | pseudoflavor = RPC_AUTH_GSS_SPKMP; | 1112 | case Opt_sec_spkmp: |
1073 | break; | 1113 | pseudoflavor = RPC_AUTH_GSS_SPKMP; |
1074 | default: | 1114 | break; |
1075 | return 0; | 1115 | default: |
1116 | dfprintk(MOUNT, | ||
1117 | "NFS: sec= option '%s' not recognized\n", p); | ||
1118 | return 0; | ||
1119 | } | ||
1120 | |||
1121 | if (!nfs_auth_info_add(&mnt->auth_info, pseudoflavor)) | ||
1122 | return 0; | ||
1076 | } | 1123 | } |
1077 | 1124 | ||
1078 | mnt->flags |= NFS_MOUNT_SECFLAVOUR; | ||
1079 | nfs_set_auth_parsed_mount_data(mnt, pseudoflavor); | ||
1080 | return 1; | 1125 | return 1; |
1081 | } | 1126 | } |
1082 | 1127 | ||
@@ -1623,12 +1668,14 @@ out_security_failure: | |||
1623 | } | 1668 | } |
1624 | 1669 | ||
1625 | /* | 1670 | /* |
1626 | * Ensure that the specified authtype in args->auth_flavors[0] is supported by | 1671 | * Ensure that a specified authtype in args->auth_info is supported by |
1627 | * the server. Returns 0 if it's ok, and -EACCES if not. | 1672 | * the server. Returns 0 and sets args->selected_flavor if it's ok, and |
1673 | * -EACCES if not. | ||
1628 | */ | 1674 | */ |
1629 | static int nfs_verify_authflavor(struct nfs_parsed_mount_data *args, | 1675 | static int nfs_verify_authflavors(struct nfs_parsed_mount_data *args, |
1630 | rpc_authflavor_t *server_authlist, unsigned int count) | 1676 | rpc_authflavor_t *server_authlist, unsigned int count) |
1631 | { | 1677 | { |
1678 | rpc_authflavor_t flavor = RPC_AUTH_MAXFLAVOR; | ||
1632 | unsigned int i; | 1679 | unsigned int i; |
1633 | 1680 | ||
1634 | /* | 1681 | /* |
@@ -1640,17 +1687,20 @@ static int nfs_verify_authflavor(struct nfs_parsed_mount_data *args, | |||
1640 | * can be used. | 1687 | * can be used. |
1641 | */ | 1688 | */ |
1642 | for (i = 0; i < count; i++) { | 1689 | for (i = 0; i < count; i++) { |
1643 | if (args->auth_flavors[0] == server_authlist[i] || | 1690 | flavor = server_authlist[i]; |
1644 | server_authlist[i] == RPC_AUTH_NULL) | 1691 | |
1692 | if (nfs_auth_info_match(&args->auth_info, flavor) || | ||
1693 | flavor == RPC_AUTH_NULL) | ||
1645 | goto out; | 1694 | goto out; |
1646 | } | 1695 | } |
1647 | 1696 | ||
1648 | dfprintk(MOUNT, "NFS: auth flavor %u not supported by server\n", | 1697 | dfprintk(MOUNT, |
1649 | args->auth_flavors[0]); | 1698 | "NFS: specified auth flavors not supported by server\n"); |
1650 | return -EACCES; | 1699 | return -EACCES; |
1651 | 1700 | ||
1652 | out: | 1701 | out: |
1653 | dfprintk(MOUNT, "NFS: using auth flavor %u\n", args->auth_flavors[0]); | 1702 | args->selected_flavor = flavor; |
1703 | dfprintk(MOUNT, "NFS: using auth flavor %u\n", args->selected_flavor); | ||
1654 | return 0; | 1704 | return 0; |
1655 | } | 1705 | } |
1656 | 1706 | ||
@@ -1738,9 +1788,10 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf | |||
1738 | * Was a sec= authflavor specified in the options? First, verify | 1788 | * Was a sec= authflavor specified in the options? First, verify |
1739 | * whether the server supports it, and then just try to use it if so. | 1789 | * whether the server supports it, and then just try to use it if so. |
1740 | */ | 1790 | */ |
1741 | if (args->auth_flavor_len > 0) { | 1791 | if (args->auth_info.flavor_len > 0) { |
1742 | status = nfs_verify_authflavor(args, authlist, authlist_len); | 1792 | status = nfs_verify_authflavors(args, authlist, authlist_len); |
1743 | dfprintk(MOUNT, "NFS: using auth flavor %u\n", args->auth_flavors[0]); | 1793 | dfprintk(MOUNT, "NFS: using auth flavor %u\n", |
1794 | args->selected_flavor); | ||
1744 | if (status) | 1795 | if (status) |
1745 | return ERR_PTR(status); | 1796 | return ERR_PTR(status); |
1746 | return nfs_mod->rpc_ops->create_server(mount_info, nfs_mod); | 1797 | return nfs_mod->rpc_ops->create_server(mount_info, nfs_mod); |
@@ -1769,7 +1820,7 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf | |||
1769 | /* Fallthrough */ | 1820 | /* Fallthrough */ |
1770 | } | 1821 | } |
1771 | dfprintk(MOUNT, "NFS: attempting to use auth flavor %u\n", flavor); | 1822 | dfprintk(MOUNT, "NFS: attempting to use auth flavor %u\n", flavor); |
1772 | nfs_set_auth_parsed_mount_data(args, flavor); | 1823 | args->selected_flavor = flavor; |
1773 | server = nfs_mod->rpc_ops->create_server(mount_info, nfs_mod); | 1824 | server = nfs_mod->rpc_ops->create_server(mount_info, nfs_mod); |
1774 | if (!IS_ERR(server)) | 1825 | if (!IS_ERR(server)) |
1775 | return server; | 1826 | return server; |
@@ -1785,7 +1836,7 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf | |||
1785 | 1836 | ||
1786 | /* Last chance! Try AUTH_UNIX */ | 1837 | /* Last chance! Try AUTH_UNIX */ |
1787 | dfprintk(MOUNT, "NFS: attempting to use auth flavor %u\n", RPC_AUTH_UNIX); | 1838 | dfprintk(MOUNT, "NFS: attempting to use auth flavor %u\n", RPC_AUTH_UNIX); |
1788 | nfs_set_auth_parsed_mount_data(args, RPC_AUTH_UNIX); | 1839 | args->selected_flavor = RPC_AUTH_UNIX; |
1789 | return nfs_mod->rpc_ops->create_server(mount_info, nfs_mod); | 1840 | return nfs_mod->rpc_ops->create_server(mount_info, nfs_mod); |
1790 | } | 1841 | } |
1791 | 1842 | ||
@@ -1972,9 +2023,9 @@ static int nfs23_validate_mount_data(void *options, | |||
1972 | args->bsize = data->bsize; | 2023 | args->bsize = data->bsize; |
1973 | 2024 | ||
1974 | if (data->flags & NFS_MOUNT_SECFLAVOUR) | 2025 | if (data->flags & NFS_MOUNT_SECFLAVOUR) |
1975 | nfs_set_auth_parsed_mount_data(args, data->pseudoflavor); | 2026 | args->selected_flavor = data->pseudoflavor; |
1976 | else | 2027 | else |
1977 | nfs_set_auth_parsed_mount_data(args, RPC_AUTH_UNIX); | 2028 | args->selected_flavor = RPC_AUTH_UNIX; |
1978 | if (!args->nfs_server.hostname) | 2029 | if (!args->nfs_server.hostname) |
1979 | goto out_nomem; | 2030 | goto out_nomem; |
1980 | 2031 | ||
@@ -2108,9 +2159,6 @@ static int nfs_validate_text_mount_data(void *options, | |||
2108 | 2159 | ||
2109 | nfs_set_port(sap, &args->nfs_server.port, port); | 2160 | nfs_set_port(sap, &args->nfs_server.port, port); |
2110 | 2161 | ||
2111 | if (args->auth_flavor_len > 1) | ||
2112 | goto out_bad_auth; | ||
2113 | |||
2114 | return nfs_parse_devname(dev_name, | 2162 | return nfs_parse_devname(dev_name, |
2115 | &args->nfs_server.hostname, | 2163 | &args->nfs_server.hostname, |
2116 | max_namelen, | 2164 | max_namelen, |
@@ -2130,10 +2178,6 @@ out_invalid_transport_udp: | |||
2130 | out_no_address: | 2178 | out_no_address: |
2131 | dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n"); | 2179 | dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n"); |
2132 | return -EINVAL; | 2180 | return -EINVAL; |
2133 | |||
2134 | out_bad_auth: | ||
2135 | dfprintk(MOUNT, "NFS: Too many RPC auth flavours specified\n"); | ||
2136 | return -EINVAL; | ||
2137 | } | 2181 | } |
2138 | 2182 | ||
2139 | static int | 2183 | static int |
@@ -2143,8 +2187,10 @@ nfs_compare_remount_data(struct nfs_server *nfss, | |||
2143 | if (data->flags != nfss->flags || | 2187 | if (data->flags != nfss->flags || |
2144 | data->rsize != nfss->rsize || | 2188 | data->rsize != nfss->rsize || |
2145 | data->wsize != nfss->wsize || | 2189 | data->wsize != nfss->wsize || |
2190 | data->version != nfss->nfs_client->rpc_ops->version || | ||
2191 | data->minorversion != nfss->nfs_client->cl_minorversion || | ||
2146 | data->retrans != nfss->client->cl_timeout->to_retries || | 2192 | data->retrans != nfss->client->cl_timeout->to_retries || |
2147 | data->auth_flavors[0] != nfss->client->cl_auth->au_flavor || | 2193 | data->selected_flavor != nfss->client->cl_auth->au_flavor || |
2148 | data->acregmin != nfss->acregmin / HZ || | 2194 | data->acregmin != nfss->acregmin / HZ || |
2149 | data->acregmax != nfss->acregmax / HZ || | 2195 | data->acregmax != nfss->acregmax / HZ || |
2150 | data->acdirmin != nfss->acdirmin / HZ || | 2196 | data->acdirmin != nfss->acdirmin / HZ || |
@@ -2189,7 +2235,8 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data) | |||
2189 | data->rsize = nfss->rsize; | 2235 | data->rsize = nfss->rsize; |
2190 | data->wsize = nfss->wsize; | 2236 | data->wsize = nfss->wsize; |
2191 | data->retrans = nfss->client->cl_timeout->to_retries; | 2237 | data->retrans = nfss->client->cl_timeout->to_retries; |
2192 | nfs_set_auth_parsed_mount_data(data, nfss->client->cl_auth->au_flavor); | 2238 | data->selected_flavor = nfss->client->cl_auth->au_flavor; |
2239 | data->auth_info = nfss->auth_info; | ||
2193 | data->acregmin = nfss->acregmin / HZ; | 2240 | data->acregmin = nfss->acregmin / HZ; |
2194 | data->acregmax = nfss->acregmax / HZ; | 2241 | data->acregmax = nfss->acregmax / HZ; |
2195 | data->acdirmin = nfss->acdirmin / HZ; | 2242 | data->acdirmin = nfss->acdirmin / HZ; |
@@ -2197,12 +2244,14 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data) | |||
2197 | data->timeo = 10U * nfss->client->cl_timeout->to_initval / HZ; | 2244 | data->timeo = 10U * nfss->client->cl_timeout->to_initval / HZ; |
2198 | data->nfs_server.port = nfss->port; | 2245 | data->nfs_server.port = nfss->port; |
2199 | data->nfs_server.addrlen = nfss->nfs_client->cl_addrlen; | 2246 | data->nfs_server.addrlen = nfss->nfs_client->cl_addrlen; |
2247 | data->version = nfsvers; | ||
2248 | data->minorversion = nfss->nfs_client->cl_minorversion; | ||
2200 | memcpy(&data->nfs_server.address, &nfss->nfs_client->cl_addr, | 2249 | memcpy(&data->nfs_server.address, &nfss->nfs_client->cl_addr, |
2201 | data->nfs_server.addrlen); | 2250 | data->nfs_server.addrlen); |
2202 | 2251 | ||
2203 | /* overwrite those values with any that were specified */ | 2252 | /* overwrite those values with any that were specified */ |
2204 | error = nfs_parse_mount_options((char *)options, data); | 2253 | error = -EINVAL; |
2205 | if (error < 0) | 2254 | if (!nfs_parse_mount_options((char *)options, data)) |
2206 | goto out; | 2255 | goto out; |
2207 | 2256 | ||
2208 | /* | 2257 | /* |
@@ -2332,7 +2381,7 @@ static int nfs_compare_mount_options(const struct super_block *s, const struct n | |||
2332 | goto Ebusy; | 2381 | goto Ebusy; |
2333 | if (a->acdirmax != b->acdirmax) | 2382 | if (a->acdirmax != b->acdirmax) |
2334 | goto Ebusy; | 2383 | goto Ebusy; |
2335 | if (b->flags & NFS_MOUNT_SECFLAVOUR && | 2384 | if (b->auth_info.flavor_len > 0 && |
2336 | clnt_a->cl_auth->au_flavor != clnt_b->cl_auth->au_flavor) | 2385 | clnt_a->cl_auth->au_flavor != clnt_b->cl_auth->au_flavor) |
2337 | goto Ebusy; | 2386 | goto Ebusy; |
2338 | return 1; | 2387 | return 1; |
@@ -2530,6 +2579,7 @@ struct dentry *nfs_fs_mount_common(struct nfs_server *server, | |||
2530 | mntroot = ERR_PTR(error); | 2579 | mntroot = ERR_PTR(error); |
2531 | goto error_splat_bdi; | 2580 | goto error_splat_bdi; |
2532 | } | 2581 | } |
2582 | server->super = s; | ||
2533 | } | 2583 | } |
2534 | 2584 | ||
2535 | if (!s->s_root) { | 2585 | if (!s->s_root) { |
@@ -2713,9 +2763,9 @@ static int nfs4_validate_mount_data(void *options, | |||
2713 | data->auth_flavours, | 2763 | data->auth_flavours, |
2714 | sizeof(pseudoflavor))) | 2764 | sizeof(pseudoflavor))) |
2715 | return -EFAULT; | 2765 | return -EFAULT; |
2716 | nfs_set_auth_parsed_mount_data(args, pseudoflavor); | 2766 | args->selected_flavor = pseudoflavor; |
2717 | } else | 2767 | } else |
2718 | nfs_set_auth_parsed_mount_data(args, RPC_AUTH_UNIX); | 2768 | args->selected_flavor = RPC_AUTH_UNIX; |
2719 | 2769 | ||
2720 | c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN); | 2770 | c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN); |
2721 | if (IS_ERR(c)) | 2771 | if (IS_ERR(c)) |
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index bb939edd4c99..0c29b1bb3936 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c | |||
@@ -493,7 +493,7 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry) | |||
493 | unsigned long long fileid; | 493 | unsigned long long fileid; |
494 | struct dentry *sdentry; | 494 | struct dentry *sdentry; |
495 | struct rpc_task *task; | 495 | struct rpc_task *task; |
496 | int error = -EIO; | 496 | int error = -EBUSY; |
497 | 497 | ||
498 | dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n", | 498 | dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n", |
499 | dentry->d_parent->d_name.name, dentry->d_name.name, | 499 | dentry->d_parent->d_name.name, dentry->d_name.name, |
@@ -503,7 +503,6 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry) | |||
503 | /* | 503 | /* |
504 | * We don't allow a dentry to be silly-renamed twice. | 504 | * We don't allow a dentry to be silly-renamed twice. |
505 | */ | 505 | */ |
506 | error = -EBUSY; | ||
507 | if (dentry->d_flags & DCACHE_NFSFS_RENAMED) | 506 | if (dentry->d_flags & DCACHE_NFSFS_RENAMED) |
508 | goto out; | 507 | goto out; |
509 | 508 | ||