diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-30 22:16:57 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-30 22:16:57 -0400 |
commit | 1fad1e9a747687a7399bf58e87974f9b1bbcae06 (patch) | |
tree | fde2dc9a35321e21c99e06d4b79d5fa06fd34679 | |
parent | bbeb0af25f493261c15ceee176c99b7fd6fd5479 (diff) | |
parent | f44106e2173f08ccb1c9195d85a6c22388b461c1 (diff) |
Merge tag 'nfs-for-3.6-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client updates from Trond Myklebust:
"Features include:
- More preparatory patches for modularising NFSv2/v3/v4. Split out
the various NFSv2/v3/v4-specific code into separate files
- More preparation for the NFSv4 migration code
- Ensure that OPEN(O_CREATE) observes the pNFS mds threshold
parameters
- pNFS fast failover when the data servers are down
- Various cleanups and debugging patches"
* tag 'nfs-for-3.6-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (67 commits)
nfs: fix fl_type tests in NFSv4 code
NFS: fix pnfs regression with directio writes
NFS: fix pnfs regression with directio reads
sunrpc: clnt: Add missing braces
nfs: fix stub return type warnings
NFS: exit_nfs_v4() shouldn't be an __exit function
SUNRPC: Add a missing spin_unlock to gss_mech_list_pseudoflavors
NFS: Split out NFS v4 client functions
NFS: Split out the NFS v4 filesystem types
NFS: Create a single nfs_clone_super() function
NFS: Split out NFS v4 server creating code
NFS: Initialize the NFS v4 client from init_nfs_v4()
NFS: Move the v4 getroot code to nfs4getroot.c
NFS: Split out NFS v4 file operations
NFS: Initialize v4 sysctls from nfs_init_v4()
NFS: Create an init_nfs_v4() function
NFS: Split out NFS v4 inode operations
NFS: Split out NFS v3 inode operations
NFS: Split out NFS v2 inode operations
NFS: Clean up nfs4_proc_setclientid() and friends
...
45 files changed, 2220 insertions, 1825 deletions
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig index f90f4f5cd421..404c6a8ac394 100644 --- a/fs/nfs/Kconfig +++ b/fs/nfs/Kconfig | |||
@@ -88,9 +88,8 @@ config NFS_V4 | |||
88 | 88 | ||
89 | config NFS_V4_1 | 89 | config NFS_V4_1 |
90 | bool "NFS client support for NFSv4.1 (EXPERIMENTAL)" | 90 | bool "NFS client support for NFSv4.1 (EXPERIMENTAL)" |
91 | depends on NFS_FS && NFS_V4 && EXPERIMENTAL | 91 | depends on NFS_V4 && EXPERIMENTAL |
92 | select SUNRPC_BACKCHANNEL | 92 | select SUNRPC_BACKCHANNEL |
93 | select PNFS_FILE_LAYOUT | ||
94 | help | 93 | help |
95 | This option enables support for minor version 1 of the NFSv4 protocol | 94 | This option enables support for minor version 1 of the NFSv4 protocol |
96 | (RFC 5661) in the kernel's NFS client. | 95 | (RFC 5661) in the kernel's NFS client. |
@@ -99,15 +98,17 @@ config NFS_V4_1 | |||
99 | 98 | ||
100 | config PNFS_FILE_LAYOUT | 99 | config PNFS_FILE_LAYOUT |
101 | tristate | 100 | tristate |
101 | depends on NFS_V4_1 | ||
102 | default m | ||
102 | 103 | ||
103 | config PNFS_BLOCK | 104 | config PNFS_BLOCK |
104 | tristate | 105 | tristate |
105 | depends on NFS_FS && NFS_V4_1 && BLK_DEV_DM | 106 | depends on NFS_V4_1 && BLK_DEV_DM |
106 | default m | 107 | default m |
107 | 108 | ||
108 | config PNFS_OBJLAYOUT | 109 | config PNFS_OBJLAYOUT |
109 | tristate | 110 | tristate |
110 | depends on NFS_FS && NFS_V4_1 && SCSI_OSD_ULD | 111 | depends on NFS_V4_1 && SCSI_OSD_ULD |
111 | default m | 112 | default m |
112 | 113 | ||
113 | config NFS_V4_1_IMPLEMENTATION_ID_DOMAIN | 114 | config NFS_V4_1_IMPLEMENTATION_ID_DOMAIN |
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile index 7ddd45d9f170..0b96c2038346 100644 --- a/fs/nfs/Makefile +++ b/fs/nfs/Makefile | |||
@@ -13,11 +13,16 @@ nfs-$(CONFIG_NFS_V2) += proc.o nfs2xdr.o | |||
13 | nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o | 13 | nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o |
14 | nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o | 14 | nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o |
15 | nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ | 15 | nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ |
16 | delegation.o idmap.o \ | 16 | nfs4super.o nfs4file.o delegation.o idmap.o \ |
17 | callback.o callback_xdr.o callback_proc.o \ | 17 | callback.o callback_xdr.o callback_proc.o \ |
18 | nfs4namespace.o | 18 | nfs4namespace.o nfs4getroot.o nfs4client.o |
19 | nfs-$(CONFIG_NFS_V4_1) += pnfs.o pnfs_dev.o | 19 | nfs-$(CONFIG_NFS_V4_1) += pnfs.o pnfs_dev.o |
20 | nfs-$(CONFIG_SYSCTL) += sysctl.o | 20 | |
21 | ifeq ($(CONFIG_SYSCTL), y) | ||
22 | nfs-y += sysctl.o | ||
23 | nfs-$(CONFIG_NFS_V4) += nfs4sysctl.o | ||
24 | endif | ||
25 | |||
21 | nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o | 26 | nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o |
22 | 27 | ||
23 | obj-$(CONFIG_PNFS_FILE_LAYOUT) += nfs_layout_nfsv41_files.o | 28 | obj-$(CONFIG_PNFS_FILE_LAYOUT) += nfs_layout_nfsv41_files.o |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index f005b5bebdc7..65afa382c5e3 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -56,35 +56,6 @@ | |||
56 | #define NFSDBG_FACILITY NFSDBG_CLIENT | 56 | #define NFSDBG_FACILITY NFSDBG_CLIENT |
57 | 57 | ||
58 | static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq); | 58 | static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq); |
59 | #ifdef CONFIG_NFS_V4 | ||
60 | |||
61 | /* | ||
62 | * Get a unique NFSv4.0 callback identifier which will be used | ||
63 | * by the V4.0 callback service to lookup the nfs_client struct | ||
64 | */ | ||
65 | static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion) | ||
66 | { | ||
67 | int ret = 0; | ||
68 | struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id); | ||
69 | |||
70 | if (clp->rpc_ops->version != 4 || minorversion != 0) | ||
71 | return ret; | ||
72 | retry: | ||
73 | if (!idr_pre_get(&nn->cb_ident_idr, GFP_KERNEL)) | ||
74 | return -ENOMEM; | ||
75 | spin_lock(&nn->nfs_client_lock); | ||
76 | ret = idr_get_new(&nn->cb_ident_idr, clp, &clp->cl_cb_ident); | ||
77 | spin_unlock(&nn->nfs_client_lock); | ||
78 | if (ret == -EAGAIN) | ||
79 | goto retry; | ||
80 | return ret; | ||
81 | } | ||
82 | #endif /* CONFIG_NFS_V4 */ | ||
83 | |||
84 | /* | ||
85 | * Turn off NFSv4 uid/gid mapping when using AUTH_SYS | ||
86 | */ | ||
87 | static bool nfs4_disable_idmapping = true; | ||
88 | 59 | ||
89 | /* | 60 | /* |
90 | * RPC cruft for NFS | 61 | * RPC cruft for NFS |
@@ -130,24 +101,13 @@ const struct rpc_program nfsacl_program = { | |||
130 | }; | 101 | }; |
131 | #endif /* CONFIG_NFS_V3_ACL */ | 102 | #endif /* CONFIG_NFS_V3_ACL */ |
132 | 103 | ||
133 | struct nfs_client_initdata { | ||
134 | unsigned long init_flags; | ||
135 | const char *hostname; | ||
136 | const struct sockaddr *addr; | ||
137 | size_t addrlen; | ||
138 | const struct nfs_rpc_ops *rpc_ops; | ||
139 | int proto; | ||
140 | u32 minorversion; | ||
141 | struct net *net; | ||
142 | }; | ||
143 | |||
144 | /* | 104 | /* |
145 | * Allocate a shared client record | 105 | * Allocate a shared client record |
146 | * | 106 | * |
147 | * Since these are allocated/deallocated very rarely, we don't | 107 | * Since these are allocated/deallocated very rarely, we don't |
148 | * bother putting them in a slab cache... | 108 | * bother putting them in a slab cache... |
149 | */ | 109 | */ |
150 | static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init) | 110 | struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init) |
151 | { | 111 | { |
152 | struct nfs_client *clp; | 112 | struct nfs_client *clp; |
153 | struct rpc_cred *cred; | 113 | struct rpc_cred *cred; |
@@ -177,18 +137,6 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
177 | clp->cl_proto = cl_init->proto; | 137 | clp->cl_proto = cl_init->proto; |
178 | clp->cl_net = get_net(cl_init->net); | 138 | clp->cl_net = get_net(cl_init->net); |
179 | 139 | ||
180 | #ifdef CONFIG_NFS_V4 | ||
181 | err = nfs_get_cb_ident_idr(clp, cl_init->minorversion); | ||
182 | if (err) | ||
183 | goto error_cleanup; | ||
184 | |||
185 | spin_lock_init(&clp->cl_lock); | ||
186 | INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state); | ||
187 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); | ||
188 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; | ||
189 | clp->cl_minorversion = cl_init->minorversion; | ||
190 | clp->cl_mvops = nfs_v4_minor_ops[cl_init->minorversion]; | ||
191 | #endif | ||
192 | cred = rpc_lookup_machine_cred("*"); | 140 | cred = rpc_lookup_machine_cred("*"); |
193 | if (!IS_ERR(cred)) | 141 | if (!IS_ERR(cred)) |
194 | clp->cl_machine_cred = cred; | 142 | clp->cl_machine_cred = cred; |
@@ -203,45 +151,6 @@ error_0: | |||
203 | } | 151 | } |
204 | 152 | ||
205 | #ifdef CONFIG_NFS_V4 | 153 | #ifdef CONFIG_NFS_V4 |
206 | #ifdef CONFIG_NFS_V4_1 | ||
207 | static void nfs4_shutdown_session(struct nfs_client *clp) | ||
208 | { | ||
209 | if (nfs4_has_session(clp)) { | ||
210 | nfs4_destroy_session(clp->cl_session); | ||
211 | nfs4_destroy_clientid(clp); | ||
212 | } | ||
213 | |||
214 | } | ||
215 | #else /* CONFIG_NFS_V4_1 */ | ||
216 | static void nfs4_shutdown_session(struct nfs_client *clp) | ||
217 | { | ||
218 | } | ||
219 | #endif /* CONFIG_NFS_V4_1 */ | ||
220 | |||
221 | /* | ||
222 | * Destroy the NFS4 callback service | ||
223 | */ | ||
224 | static void nfs4_destroy_callback(struct nfs_client *clp) | ||
225 | { | ||
226 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | ||
227 | nfs_callback_down(clp->cl_mvops->minor_version); | ||
228 | } | ||
229 | |||
230 | static void nfs4_shutdown_client(struct nfs_client *clp) | ||
231 | { | ||
232 | if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state)) | ||
233 | nfs4_kill_renewd(clp); | ||
234 | nfs4_shutdown_session(clp); | ||
235 | nfs4_destroy_callback(clp); | ||
236 | if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state)) | ||
237 | nfs_idmap_delete(clp); | ||
238 | |||
239 | rpc_destroy_wait_queue(&clp->cl_rpcwaitq); | ||
240 | kfree(clp->cl_serverowner); | ||
241 | kfree(clp->cl_serverscope); | ||
242 | kfree(clp->cl_implid); | ||
243 | } | ||
244 | |||
245 | /* idr_remove_all is not needed as all id's are removed by nfs_put_client */ | 154 | /* idr_remove_all is not needed as all id's are removed by nfs_put_client */ |
246 | void nfs_cleanup_cb_ident_idr(struct net *net) | 155 | void nfs_cleanup_cb_ident_idr(struct net *net) |
247 | { | 156 | { |
@@ -264,16 +173,7 @@ static void pnfs_init_server(struct nfs_server *server) | |||
264 | rpc_init_wait_queue(&server->roc_rpcwaitq, "pNFS ROC"); | 173 | rpc_init_wait_queue(&server->roc_rpcwaitq, "pNFS ROC"); |
265 | } | 174 | } |
266 | 175 | ||
267 | static void nfs4_destroy_server(struct nfs_server *server) | ||
268 | { | ||
269 | nfs4_purge_state_owners(server); | ||
270 | } | ||
271 | |||
272 | #else | 176 | #else |
273 | static void nfs4_shutdown_client(struct nfs_client *clp) | ||
274 | { | ||
275 | } | ||
276 | |||
277 | void nfs_cleanup_cb_ident_idr(struct net *net) | 177 | void nfs_cleanup_cb_ident_idr(struct net *net) |
278 | { | 178 | { |
279 | } | 179 | } |
@@ -291,12 +191,10 @@ static void pnfs_init_server(struct nfs_server *server) | |||
291 | /* | 191 | /* |
292 | * Destroy a shared client record | 192 | * Destroy a shared client record |
293 | */ | 193 | */ |
294 | static void nfs_free_client(struct nfs_client *clp) | 194 | void nfs_free_client(struct nfs_client *clp) |
295 | { | 195 | { |
296 | dprintk("--> nfs_free_client(%u)\n", clp->rpc_ops->version); | 196 | dprintk("--> nfs_free_client(%u)\n", clp->rpc_ops->version); |
297 | 197 | ||
298 | nfs4_shutdown_client(clp); | ||
299 | |||
300 | nfs_fscache_release_client_cookie(clp); | 198 | nfs_fscache_release_client_cookie(clp); |
301 | 199 | ||
302 | /* -EIO all pending I/O */ | 200 | /* -EIO all pending I/O */ |
@@ -333,7 +231,7 @@ void nfs_put_client(struct nfs_client *clp) | |||
333 | 231 | ||
334 | BUG_ON(!list_empty(&clp->cl_superblocks)); | 232 | BUG_ON(!list_empty(&clp->cl_superblocks)); |
335 | 233 | ||
336 | nfs_free_client(clp); | 234 | clp->rpc_ops->free_client(clp); |
337 | } | 235 | } |
338 | } | 236 | } |
339 | EXPORT_SYMBOL_GPL(nfs_put_client); | 237 | EXPORT_SYMBOL_GPL(nfs_put_client); |
@@ -412,8 +310,8 @@ static int nfs_sockaddr_cmp_ip4(const struct sockaddr *sa1, | |||
412 | * Test if two socket addresses represent the same actual socket, | 310 | * Test if two socket addresses represent the same actual socket, |
413 | * by comparing (only) relevant fields, excluding the port number. | 311 | * by comparing (only) relevant fields, excluding the port number. |
414 | */ | 312 | */ |
415 | static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, | 313 | int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, |
416 | const struct sockaddr *sa2) | 314 | const struct sockaddr *sa2) |
417 | { | 315 | { |
418 | if (sa1->sa_family != sa2->sa_family) | 316 | if (sa1->sa_family != sa2->sa_family) |
419 | return 0; | 317 | return 0; |
@@ -447,33 +345,6 @@ static int nfs_sockaddr_cmp(const struct sockaddr *sa1, | |||
447 | return 0; | 345 | return 0; |
448 | } | 346 | } |
449 | 347 | ||
450 | #if defined(CONFIG_NFS_V4_1) | ||
451 | /* Common match routine for v4.0 and v4.1 callback services */ | ||
452 | static bool nfs4_cb_match_client(const struct sockaddr *addr, | ||
453 | struct nfs_client *clp, u32 minorversion) | ||
454 | { | ||
455 | struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; | ||
456 | |||
457 | /* Don't match clients that failed to initialise */ | ||
458 | if (!(clp->cl_cons_state == NFS_CS_READY || | ||
459 | clp->cl_cons_state == NFS_CS_SESSION_INITING)) | ||
460 | return false; | ||
461 | |||
462 | smp_rmb(); | ||
463 | |||
464 | /* Match the version and minorversion */ | ||
465 | if (clp->rpc_ops->version != 4 || | ||
466 | clp->cl_minorversion != minorversion) | ||
467 | return false; | ||
468 | |||
469 | /* Match only the IP address, not the port number */ | ||
470 | if (!nfs_sockaddr_match_ipaddr(addr, clap)) | ||
471 | return false; | ||
472 | |||
473 | return true; | ||
474 | } | ||
475 | #endif /* CONFIG_NFS_V4_1 */ | ||
476 | |||
477 | /* | 348 | /* |
478 | * Find an nfs_client on the list that matches the initialisation data | 349 | * Find an nfs_client on the list that matches the initialisation data |
479 | * that is supplied. | 350 | * that is supplied. |
@@ -552,7 +423,7 @@ nfs_found_client(const struct nfs_client_initdata *cl_init, | |||
552 | * Look up a client by IP address and protocol version | 423 | * Look up a client by IP address and protocol version |
553 | * - creates a new record if one doesn't yet exist | 424 | * - creates a new record if one doesn't yet exist |
554 | */ | 425 | */ |
555 | static struct nfs_client * | 426 | struct nfs_client * |
556 | nfs_get_client(const struct nfs_client_initdata *cl_init, | 427 | nfs_get_client(const struct nfs_client_initdata *cl_init, |
557 | const struct rpc_timeout *timeparms, | 428 | const struct rpc_timeout *timeparms, |
558 | const char *ip_addr, | 429 | const char *ip_addr, |
@@ -572,7 +443,7 @@ nfs_get_client(const struct nfs_client_initdata *cl_init, | |||
572 | if (clp) { | 443 | if (clp) { |
573 | spin_unlock(&nn->nfs_client_lock); | 444 | spin_unlock(&nn->nfs_client_lock); |
574 | if (new) | 445 | if (new) |
575 | nfs_free_client(new); | 446 | new->rpc_ops->free_client(new); |
576 | return nfs_found_client(cl_init, clp); | 447 | return nfs_found_client(cl_init, clp); |
577 | } | 448 | } |
578 | if (new) { | 449 | if (new) { |
@@ -586,7 +457,7 @@ nfs_get_client(const struct nfs_client_initdata *cl_init, | |||
586 | 457 | ||
587 | spin_unlock(&nn->nfs_client_lock); | 458 | spin_unlock(&nn->nfs_client_lock); |
588 | 459 | ||
589 | new = nfs_alloc_client(cl_init); | 460 | new = cl_init->rpc_ops->alloc_client(cl_init); |
590 | } while (!IS_ERR(new)); | 461 | } while (!IS_ERR(new)); |
591 | 462 | ||
592 | dprintk("<-- nfs_get_client() Failed to find %s (%ld)\n", | 463 | dprintk("<-- nfs_get_client() Failed to find %s (%ld)\n", |
@@ -607,7 +478,7 @@ void nfs_mark_client_ready(struct nfs_client *clp, int state) | |||
607 | /* | 478 | /* |
608 | * Initialise the timeout values for a connection | 479 | * Initialise the timeout values for a connection |
609 | */ | 480 | */ |
610 | static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, | 481 | void nfs_init_timeout_values(struct rpc_timeout *to, int proto, |
611 | unsigned int timeo, unsigned int retrans) | 482 | unsigned int timeo, unsigned int retrans) |
612 | { | 483 | { |
613 | to->to_initval = timeo * HZ / 10; | 484 | to->to_initval = timeo * HZ / 10; |
@@ -648,9 +519,9 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, | |||
648 | /* | 519 | /* |
649 | * Create an RPC client handle | 520 | * Create an RPC client handle |
650 | */ | 521 | */ |
651 | static int nfs_create_rpc_client(struct nfs_client *clp, | 522 | int nfs_create_rpc_client(struct nfs_client *clp, |
652 | const struct rpc_timeout *timeparms, | 523 | const struct rpc_timeout *timeparms, |
653 | rpc_authflavor_t flavor) | 524 | rpc_authflavor_t flavor) |
654 | { | 525 | { |
655 | struct rpc_clnt *clnt = NULL; | 526 | struct rpc_clnt *clnt = NULL; |
656 | struct rpc_create_args args = { | 527 | struct rpc_create_args args = { |
@@ -767,7 +638,7 @@ static inline void nfs_init_server_aclclient(struct nfs_server *server) | |||
767 | /* | 638 | /* |
768 | * Create a general RPC client | 639 | * Create a general RPC client |
769 | */ | 640 | */ |
770 | static int nfs_init_server_rpcclient(struct nfs_server *server, | 641 | int nfs_init_server_rpcclient(struct nfs_server *server, |
771 | const struct rpc_timeout *timeo, | 642 | const struct rpc_timeout *timeo, |
772 | rpc_authflavor_t pseudoflavour) | 643 | rpc_authflavor_t pseudoflavour) |
773 | { | 644 | { |
@@ -975,7 +846,6 @@ static void nfs_server_set_fsinfo(struct nfs_server *server, | |||
975 | server->wsize = NFS_MAX_FILE_IO_SIZE; | 846 | server->wsize = NFS_MAX_FILE_IO_SIZE; |
976 | server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | 847 | server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; |
977 | server->pnfs_blksize = fsinfo->blksize; | 848 | server->pnfs_blksize = fsinfo->blksize; |
978 | set_pnfs_layoutdriver(server, mntfh, fsinfo->layouttype); | ||
979 | 849 | ||
980 | server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL); | 850 | server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL); |
981 | 851 | ||
@@ -1001,7 +871,7 @@ static void nfs_server_set_fsinfo(struct nfs_server *server, | |||
1001 | /* | 871 | /* |
1002 | * Probe filesystem information, including the FSID on v2/v3 | 872 | * Probe filesystem information, including the FSID on v2/v3 |
1003 | */ | 873 | */ |
1004 | static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, struct nfs_fattr *fattr) | 874 | int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, struct nfs_fattr *fattr) |
1005 | { | 875 | { |
1006 | struct nfs_fsinfo fsinfo; | 876 | struct nfs_fsinfo fsinfo; |
1007 | struct nfs_client *clp = server->nfs_client; | 877 | struct nfs_client *clp = server->nfs_client; |
@@ -1045,7 +915,7 @@ out_error: | |||
1045 | /* | 915 | /* |
1046 | * Copy useful information when duplicating a server record | 916 | * Copy useful information when duplicating a server record |
1047 | */ | 917 | */ |
1048 | static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *source) | 918 | void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *source) |
1049 | { | 919 | { |
1050 | target->flags = source->flags; | 920 | target->flags = source->flags; |
1051 | target->rsize = source->rsize; | 921 | target->rsize = source->rsize; |
@@ -1058,7 +928,7 @@ static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_serve | |||
1058 | target->options = source->options; | 928 | target->options = source->options; |
1059 | } | 929 | } |
1060 | 930 | ||
1061 | static void nfs_server_insert_lists(struct nfs_server *server) | 931 | void nfs_server_insert_lists(struct nfs_server *server) |
1062 | { | 932 | { |
1063 | struct nfs_client *clp = server->nfs_client; | 933 | struct nfs_client *clp = server->nfs_client; |
1064 | struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id); | 934 | struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id); |
@@ -1092,7 +962,7 @@ static void nfs_server_remove_lists(struct nfs_server *server) | |||
1092 | /* | 962 | /* |
1093 | * Allocate and initialise a server record | 963 | * Allocate and initialise a server record |
1094 | */ | 964 | */ |
1095 | static struct nfs_server *nfs_alloc_server(void) | 965 | struct nfs_server *nfs_alloc_server(void) |
1096 | { | 966 | { |
1097 | struct nfs_server *server; | 967 | struct nfs_server *server; |
1098 | 968 | ||
@@ -1138,7 +1008,6 @@ void nfs_free_server(struct nfs_server *server) | |||
1138 | dprintk("--> nfs_free_server()\n"); | 1008 | dprintk("--> nfs_free_server()\n"); |
1139 | 1009 | ||
1140 | nfs_server_remove_lists(server); | 1010 | nfs_server_remove_lists(server); |
1141 | unset_pnfs_layoutdriver(server); | ||
1142 | 1011 | ||
1143 | if (server->destroy != NULL) | 1012 | if (server->destroy != NULL) |
1144 | server->destroy(server); | 1013 | server->destroy(server); |
@@ -1226,522 +1095,6 @@ error: | |||
1226 | return ERR_PTR(error); | 1095 | return ERR_PTR(error); |
1227 | } | 1096 | } |
1228 | 1097 | ||
1229 | #ifdef CONFIG_NFS_V4 | ||
1230 | /* | ||
1231 | * NFSv4.0 callback thread helper | ||
1232 | * | ||
1233 | * Find a client by callback identifier | ||
1234 | */ | ||
1235 | struct nfs_client * | ||
1236 | nfs4_find_client_ident(struct net *net, int cb_ident) | ||
1237 | { | ||
1238 | struct nfs_client *clp; | ||
1239 | struct nfs_net *nn = net_generic(net, nfs_net_id); | ||
1240 | |||
1241 | spin_lock(&nn->nfs_client_lock); | ||
1242 | clp = idr_find(&nn->cb_ident_idr, cb_ident); | ||
1243 | if (clp) | ||
1244 | atomic_inc(&clp->cl_count); | ||
1245 | spin_unlock(&nn->nfs_client_lock); | ||
1246 | return clp; | ||
1247 | } | ||
1248 | |||
1249 | #if defined(CONFIG_NFS_V4_1) | ||
1250 | /* | ||
1251 | * NFSv4.1 callback thread helper | ||
1252 | * For CB_COMPOUND calls, find a client by IP address, protocol version, | ||
1253 | * minorversion, and sessionID | ||
1254 | * | ||
1255 | * Returns NULL if no such client | ||
1256 | */ | ||
1257 | struct nfs_client * | ||
1258 | nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr, | ||
1259 | struct nfs4_sessionid *sid) | ||
1260 | { | ||
1261 | struct nfs_client *clp; | ||
1262 | struct nfs_net *nn = net_generic(net, nfs_net_id); | ||
1263 | |||
1264 | spin_lock(&nn->nfs_client_lock); | ||
1265 | list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) { | ||
1266 | if (nfs4_cb_match_client(addr, clp, 1) == false) | ||
1267 | continue; | ||
1268 | |||
1269 | if (!nfs4_has_session(clp)) | ||
1270 | continue; | ||
1271 | |||
1272 | /* Match sessionid*/ | ||
1273 | if (memcmp(clp->cl_session->sess_id.data, | ||
1274 | sid->data, NFS4_MAX_SESSIONID_LEN) != 0) | ||
1275 | continue; | ||
1276 | |||
1277 | atomic_inc(&clp->cl_count); | ||
1278 | spin_unlock(&nn->nfs_client_lock); | ||
1279 | return clp; | ||
1280 | } | ||
1281 | spin_unlock(&nn->nfs_client_lock); | ||
1282 | return NULL; | ||
1283 | } | ||
1284 | |||
1285 | #else /* CONFIG_NFS_V4_1 */ | ||
1286 | |||
1287 | struct nfs_client * | ||
1288 | nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr, | ||
1289 | struct nfs4_sessionid *sid) | ||
1290 | { | ||
1291 | return NULL; | ||
1292 | } | ||
1293 | #endif /* CONFIG_NFS_V4_1 */ | ||
1294 | |||
1295 | /* | ||
1296 | * Initialize the NFS4 callback service | ||
1297 | */ | ||
1298 | static int nfs4_init_callback(struct nfs_client *clp) | ||
1299 | { | ||
1300 | int error; | ||
1301 | |||
1302 | if (clp->rpc_ops->version == 4) { | ||
1303 | struct rpc_xprt *xprt; | ||
1304 | |||
1305 | xprt = rcu_dereference_raw(clp->cl_rpcclient->cl_xprt); | ||
1306 | |||
1307 | if (nfs4_has_session(clp)) { | ||
1308 | error = xprt_setup_backchannel(xprt, | ||
1309 | NFS41_BC_MIN_CALLBACKS); | ||
1310 | if (error < 0) | ||
1311 | return error; | ||
1312 | } | ||
1313 | |||
1314 | error = nfs_callback_up(clp->cl_mvops->minor_version, xprt); | ||
1315 | if (error < 0) { | ||
1316 | dprintk("%s: failed to start callback. Error = %d\n", | ||
1317 | __func__, error); | ||
1318 | return error; | ||
1319 | } | ||
1320 | __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state); | ||
1321 | } | ||
1322 | return 0; | ||
1323 | } | ||
1324 | |||
1325 | /* | ||
1326 | * Initialize the minor version specific parts of an NFS4 client record | ||
1327 | */ | ||
1328 | static int nfs4_init_client_minor_version(struct nfs_client *clp) | ||
1329 | { | ||
1330 | #if defined(CONFIG_NFS_V4_1) | ||
1331 | if (clp->cl_mvops->minor_version) { | ||
1332 | struct nfs4_session *session = NULL; | ||
1333 | /* | ||
1334 | * Create the session and mark it expired. | ||
1335 | * When a SEQUENCE operation encounters the expired session | ||
1336 | * it will do session recovery to initialize it. | ||
1337 | */ | ||
1338 | session = nfs4_alloc_session(clp); | ||
1339 | if (!session) | ||
1340 | return -ENOMEM; | ||
1341 | |||
1342 | clp->cl_session = session; | ||
1343 | /* | ||
1344 | * The create session reply races with the server back | ||
1345 | * channel probe. Mark the client NFS_CS_SESSION_INITING | ||
1346 | * so that the client back channel can find the | ||
1347 | * nfs_client struct | ||
1348 | */ | ||
1349 | nfs_mark_client_ready(clp, NFS_CS_SESSION_INITING); | ||
1350 | } | ||
1351 | #endif /* CONFIG_NFS_V4_1 */ | ||
1352 | |||
1353 | return nfs4_init_callback(clp); | ||
1354 | } | ||
1355 | |||
1356 | /** | ||
1357 | * nfs4_init_client - Initialise an NFS4 client record | ||
1358 | * | ||
1359 | * @clp: nfs_client to initialise | ||
1360 | * @timeparms: timeout parameters for underlying RPC transport | ||
1361 | * @ip_addr: callback IP address in presentation format | ||
1362 | * @authflavor: authentication flavor for underlying RPC transport | ||
1363 | * | ||
1364 | * Returns pointer to an NFS client, or an ERR_PTR value. | ||
1365 | */ | ||
1366 | struct nfs_client *nfs4_init_client(struct nfs_client *clp, | ||
1367 | const struct rpc_timeout *timeparms, | ||
1368 | const char *ip_addr, | ||
1369 | rpc_authflavor_t authflavour) | ||
1370 | { | ||
1371 | char buf[INET6_ADDRSTRLEN + 1]; | ||
1372 | int error; | ||
1373 | |||
1374 | if (clp->cl_cons_state == NFS_CS_READY) { | ||
1375 | /* the client is initialised already */ | ||
1376 | dprintk("<-- nfs4_init_client() = 0 [already %p]\n", clp); | ||
1377 | return clp; | ||
1378 | } | ||
1379 | |||
1380 | /* Check NFS protocol revision and initialize RPC op vector */ | ||
1381 | clp->rpc_ops = &nfs_v4_clientops; | ||
1382 | |||
1383 | __set_bit(NFS_CS_DISCRTRY, &clp->cl_flags); | ||
1384 | error = nfs_create_rpc_client(clp, timeparms, authflavour); | ||
1385 | if (error < 0) | ||
1386 | goto error; | ||
1387 | |||
1388 | /* If no clientaddr= option was specified, find a usable cb address */ | ||
1389 | if (ip_addr == NULL) { | ||
1390 | struct sockaddr_storage cb_addr; | ||
1391 | struct sockaddr *sap = (struct sockaddr *)&cb_addr; | ||
1392 | |||
1393 | error = rpc_localaddr(clp->cl_rpcclient, sap, sizeof(cb_addr)); | ||
1394 | if (error < 0) | ||
1395 | goto error; | ||
1396 | error = rpc_ntop(sap, buf, sizeof(buf)); | ||
1397 | if (error < 0) | ||
1398 | goto error; | ||
1399 | ip_addr = (const char *)buf; | ||
1400 | } | ||
1401 | strlcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr)); | ||
1402 | |||
1403 | error = nfs_idmap_new(clp); | ||
1404 | if (error < 0) { | ||
1405 | dprintk("%s: failed to create idmapper. Error = %d\n", | ||
1406 | __func__, error); | ||
1407 | goto error; | ||
1408 | } | ||
1409 | __set_bit(NFS_CS_IDMAP, &clp->cl_res_state); | ||
1410 | |||
1411 | error = nfs4_init_client_minor_version(clp); | ||
1412 | if (error < 0) | ||
1413 | goto error; | ||
1414 | |||
1415 | if (!nfs4_has_session(clp)) | ||
1416 | nfs_mark_client_ready(clp, NFS_CS_READY); | ||
1417 | return clp; | ||
1418 | |||
1419 | error: | ||
1420 | nfs_mark_client_ready(clp, error); | ||
1421 | nfs_put_client(clp); | ||
1422 | dprintk("<-- nfs4_init_client() = xerror %d\n", error); | ||
1423 | return ERR_PTR(error); | ||
1424 | } | ||
1425 | |||
1426 | /* | ||
1427 | * Set up an NFS4 client | ||
1428 | */ | ||
1429 | static int nfs4_set_client(struct nfs_server *server, | ||
1430 | const char *hostname, | ||
1431 | const struct sockaddr *addr, | ||
1432 | const size_t addrlen, | ||
1433 | const char *ip_addr, | ||
1434 | rpc_authflavor_t authflavour, | ||
1435 | int proto, const struct rpc_timeout *timeparms, | ||
1436 | u32 minorversion, struct net *net) | ||
1437 | { | ||
1438 | struct nfs_client_initdata cl_init = { | ||
1439 | .hostname = hostname, | ||
1440 | .addr = addr, | ||
1441 | .addrlen = addrlen, | ||
1442 | .rpc_ops = &nfs_v4_clientops, | ||
1443 | .proto = proto, | ||
1444 | .minorversion = minorversion, | ||
1445 | .net = net, | ||
1446 | }; | ||
1447 | struct nfs_client *clp; | ||
1448 | int error; | ||
1449 | |||
1450 | dprintk("--> nfs4_set_client()\n"); | ||
1451 | |||
1452 | if (server->flags & NFS_MOUNT_NORESVPORT) | ||
1453 | set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags); | ||
1454 | |||
1455 | /* Allocate or find a client reference we can use */ | ||
1456 | clp = nfs_get_client(&cl_init, timeparms, ip_addr, authflavour); | ||
1457 | if (IS_ERR(clp)) { | ||
1458 | error = PTR_ERR(clp); | ||
1459 | goto error; | ||
1460 | } | ||
1461 | |||
1462 | /* | ||
1463 | * Query for the lease time on clientid setup or renewal | ||
1464 | * | ||
1465 | * Note that this will be set on nfs_clients that were created | ||
1466 | * only for the DS role and did not set this bit, but now will | ||
1467 | * serve a dual role. | ||
1468 | */ | ||
1469 | set_bit(NFS_CS_CHECK_LEASE_TIME, &clp->cl_res_state); | ||
1470 | |||
1471 | server->nfs_client = clp; | ||
1472 | dprintk("<-- nfs4_set_client() = 0 [new %p]\n", clp); | ||
1473 | return 0; | ||
1474 | error: | ||
1475 | dprintk("<-- nfs4_set_client() = xerror %d\n", error); | ||
1476 | return error; | ||
1477 | } | ||
1478 | |||
1479 | /* | ||
1480 | * Set up a pNFS Data Server client. | ||
1481 | * | ||
1482 | * Return any existing nfs_client that matches server address,port,version | ||
1483 | * and minorversion. | ||
1484 | * | ||
1485 | * For a new nfs_client, use a soft mount (default), a low retrans and a | ||
1486 | * low timeout interval so that if a connection is lost, we retry through | ||
1487 | * the MDS. | ||
1488 | */ | ||
1489 | struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp, | ||
1490 | const struct sockaddr *ds_addr, int ds_addrlen, | ||
1491 | int ds_proto, unsigned int ds_timeo, unsigned int ds_retrans) | ||
1492 | { | ||
1493 | struct nfs_client_initdata cl_init = { | ||
1494 | .addr = ds_addr, | ||
1495 | .addrlen = ds_addrlen, | ||
1496 | .rpc_ops = &nfs_v4_clientops, | ||
1497 | .proto = ds_proto, | ||
1498 | .minorversion = mds_clp->cl_minorversion, | ||
1499 | .net = mds_clp->cl_net, | ||
1500 | }; | ||
1501 | struct rpc_timeout ds_timeout; | ||
1502 | struct nfs_client *clp; | ||
1503 | |||
1504 | /* | ||
1505 | * Set an authflavor equual to the MDS value. Use the MDS nfs_client | ||
1506 | * cl_ipaddr so as to use the same EXCHANGE_ID co_ownerid as the MDS | ||
1507 | * (section 13.1 RFC 5661). | ||
1508 | */ | ||
1509 | nfs_init_timeout_values(&ds_timeout, ds_proto, ds_timeo, ds_retrans); | ||
1510 | clp = nfs_get_client(&cl_init, &ds_timeout, mds_clp->cl_ipaddr, | ||
1511 | mds_clp->cl_rpcclient->cl_auth->au_flavor); | ||
1512 | |||
1513 | dprintk("<-- %s %p\n", __func__, clp); | ||
1514 | return clp; | ||
1515 | } | ||
1516 | EXPORT_SYMBOL_GPL(nfs4_set_ds_client); | ||
1517 | |||
1518 | /* | ||
1519 | * Session has been established, and the client marked ready. | ||
1520 | * Set the mount rsize and wsize with negotiated fore channel | ||
1521 | * attributes which will be bound checked in nfs_server_set_fsinfo. | ||
1522 | */ | ||
1523 | static void nfs4_session_set_rwsize(struct nfs_server *server) | ||
1524 | { | ||
1525 | #ifdef CONFIG_NFS_V4_1 | ||
1526 | struct nfs4_session *sess; | ||
1527 | u32 server_resp_sz; | ||
1528 | u32 server_rqst_sz; | ||
1529 | |||
1530 | if (!nfs4_has_session(server->nfs_client)) | ||
1531 | return; | ||
1532 | sess = server->nfs_client->cl_session; | ||
1533 | server_resp_sz = sess->fc_attrs.max_resp_sz - nfs41_maxread_overhead; | ||
1534 | server_rqst_sz = sess->fc_attrs.max_rqst_sz - nfs41_maxwrite_overhead; | ||
1535 | |||
1536 | if (server->rsize > server_resp_sz) | ||
1537 | server->rsize = server_resp_sz; | ||
1538 | if (server->wsize > server_rqst_sz) | ||
1539 | server->wsize = server_rqst_sz; | ||
1540 | #endif /* CONFIG_NFS_V4_1 */ | ||
1541 | } | ||
1542 | |||
1543 | static int nfs4_server_common_setup(struct nfs_server *server, | ||
1544 | struct nfs_fh *mntfh) | ||
1545 | { | ||
1546 | struct nfs_fattr *fattr; | ||
1547 | int error; | ||
1548 | |||
1549 | BUG_ON(!server->nfs_client); | ||
1550 | BUG_ON(!server->nfs_client->rpc_ops); | ||
1551 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | ||
1552 | |||
1553 | /* data servers support only a subset of NFSv4.1 */ | ||
1554 | if (is_ds_only_client(server->nfs_client)) | ||
1555 | return -EPROTONOSUPPORT; | ||
1556 | |||
1557 | fattr = nfs_alloc_fattr(); | ||
1558 | if (fattr == NULL) | ||
1559 | return -ENOMEM; | ||
1560 | |||
1561 | /* We must ensure the session is initialised first */ | ||
1562 | error = nfs4_init_session(server); | ||
1563 | if (error < 0) | ||
1564 | goto out; | ||
1565 | |||
1566 | /* Probe the root fh to retrieve its FSID and filehandle */ | ||
1567 | error = nfs4_get_rootfh(server, mntfh); | ||
1568 | if (error < 0) | ||
1569 | goto out; | ||
1570 | |||
1571 | dprintk("Server FSID: %llx:%llx\n", | ||
1572 | (unsigned long long) server->fsid.major, | ||
1573 | (unsigned long long) server->fsid.minor); | ||
1574 | dprintk("Mount FH: %d\n", mntfh->size); | ||
1575 | |||
1576 | nfs4_session_set_rwsize(server); | ||
1577 | |||
1578 | error = nfs_probe_fsinfo(server, mntfh, fattr); | ||
1579 | if (error < 0) | ||
1580 | goto out; | ||
1581 | |||
1582 | if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN) | ||
1583 | server->namelen = NFS4_MAXNAMLEN; | ||
1584 | |||
1585 | nfs_server_insert_lists(server); | ||
1586 | server->mount_time = jiffies; | ||
1587 | server->destroy = nfs4_destroy_server; | ||
1588 | out: | ||
1589 | nfs_free_fattr(fattr); | ||
1590 | return error; | ||
1591 | } | ||
1592 | |||
1593 | /* | ||
1594 | * Create a version 4 volume record | ||
1595 | */ | ||
1596 | static int nfs4_init_server(struct nfs_server *server, | ||
1597 | const struct nfs_parsed_mount_data *data) | ||
1598 | { | ||
1599 | struct rpc_timeout timeparms; | ||
1600 | int error; | ||
1601 | |||
1602 | dprintk("--> nfs4_init_server()\n"); | ||
1603 | |||
1604 | nfs_init_timeout_values(&timeparms, data->nfs_server.protocol, | ||
1605 | data->timeo, data->retrans); | ||
1606 | |||
1607 | /* Initialise the client representation from the mount data */ | ||
1608 | server->flags = data->flags; | ||
1609 | server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR|NFS_CAP_POSIX_LOCK; | ||
1610 | if (!(data->flags & NFS_MOUNT_NORDIRPLUS)) | ||
1611 | server->caps |= NFS_CAP_READDIRPLUS; | ||
1612 | server->options = data->options; | ||
1613 | |||
1614 | /* Get a client record */ | ||
1615 | error = nfs4_set_client(server, | ||
1616 | data->nfs_server.hostname, | ||
1617 | (const struct sockaddr *)&data->nfs_server.address, | ||
1618 | data->nfs_server.addrlen, | ||
1619 | data->client_address, | ||
1620 | data->auth_flavors[0], | ||
1621 | data->nfs_server.protocol, | ||
1622 | &timeparms, | ||
1623 | data->minorversion, | ||
1624 | data->net); | ||
1625 | if (error < 0) | ||
1626 | goto error; | ||
1627 | |||
1628 | /* | ||
1629 | * Don't use NFS uid/gid mapping if we're using AUTH_SYS or lower | ||
1630 | * authentication. | ||
1631 | */ | ||
1632 | if (nfs4_disable_idmapping && data->auth_flavors[0] == RPC_AUTH_UNIX) | ||
1633 | server->caps |= NFS_CAP_UIDGID_NOMAP; | ||
1634 | |||
1635 | if (data->rsize) | ||
1636 | server->rsize = nfs_block_size(data->rsize, NULL); | ||
1637 | if (data->wsize) | ||
1638 | server->wsize = nfs_block_size(data->wsize, NULL); | ||
1639 | |||
1640 | server->acregmin = data->acregmin * HZ; | ||
1641 | server->acregmax = data->acregmax * HZ; | ||
1642 | server->acdirmin = data->acdirmin * HZ; | ||
1643 | server->acdirmax = data->acdirmax * HZ; | ||
1644 | |||
1645 | server->port = data->nfs_server.port; | ||
1646 | |||
1647 | error = nfs_init_server_rpcclient(server, &timeparms, data->auth_flavors[0]); | ||
1648 | |||
1649 | error: | ||
1650 | /* Done */ | ||
1651 | dprintk("<-- nfs4_init_server() = %d\n", error); | ||
1652 | return error; | ||
1653 | } | ||
1654 | |||
1655 | /* | ||
1656 | * Create a version 4 volume record | ||
1657 | * - keyed on server and FSID | ||
1658 | */ | ||
1659 | struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, | ||
1660 | struct nfs_fh *mntfh) | ||
1661 | { | ||
1662 | struct nfs_server *server; | ||
1663 | int error; | ||
1664 | |||
1665 | dprintk("--> nfs4_create_server()\n"); | ||
1666 | |||
1667 | server = nfs_alloc_server(); | ||
1668 | if (!server) | ||
1669 | return ERR_PTR(-ENOMEM); | ||
1670 | |||
1671 | /* set up the general RPC client */ | ||
1672 | error = nfs4_init_server(server, data); | ||
1673 | if (error < 0) | ||
1674 | goto error; | ||
1675 | |||
1676 | error = nfs4_server_common_setup(server, mntfh); | ||
1677 | if (error < 0) | ||
1678 | goto error; | ||
1679 | |||
1680 | dprintk("<-- nfs4_create_server() = %p\n", server); | ||
1681 | return server; | ||
1682 | |||
1683 | error: | ||
1684 | nfs_free_server(server); | ||
1685 | dprintk("<-- nfs4_create_server() = error %d\n", error); | ||
1686 | return ERR_PTR(error); | ||
1687 | } | ||
1688 | |||
1689 | /* | ||
1690 | * Create an NFS4 referral server record | ||
1691 | */ | ||
1692 | struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | ||
1693 | struct nfs_fh *mntfh) | ||
1694 | { | ||
1695 | struct nfs_client *parent_client; | ||
1696 | struct nfs_server *server, *parent_server; | ||
1697 | int error; | ||
1698 | |||
1699 | dprintk("--> nfs4_create_referral_server()\n"); | ||
1700 | |||
1701 | server = nfs_alloc_server(); | ||
1702 | if (!server) | ||
1703 | return ERR_PTR(-ENOMEM); | ||
1704 | |||
1705 | parent_server = NFS_SB(data->sb); | ||
1706 | parent_client = parent_server->nfs_client; | ||
1707 | |||
1708 | /* Initialise the client representation from the parent server */ | ||
1709 | nfs_server_copy_userdata(server, parent_server); | ||
1710 | server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR; | ||
1711 | |||
1712 | /* Get a client representation. | ||
1713 | * Note: NFSv4 always uses TCP, */ | ||
1714 | error = nfs4_set_client(server, data->hostname, | ||
1715 | data->addr, | ||
1716 | data->addrlen, | ||
1717 | parent_client->cl_ipaddr, | ||
1718 | data->authflavor, | ||
1719 | rpc_protocol(parent_server->client), | ||
1720 | parent_server->client->cl_timeout, | ||
1721 | parent_client->cl_mvops->minor_version, | ||
1722 | parent_client->cl_net); | ||
1723 | if (error < 0) | ||
1724 | goto error; | ||
1725 | |||
1726 | error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout, data->authflavor); | ||
1727 | if (error < 0) | ||
1728 | goto error; | ||
1729 | |||
1730 | error = nfs4_server_common_setup(server, mntfh); | ||
1731 | if (error < 0) | ||
1732 | goto error; | ||
1733 | |||
1734 | dprintk("<-- nfs_create_referral_server() = %p\n", server); | ||
1735 | return server; | ||
1736 | |||
1737 | error: | ||
1738 | nfs_free_server(server); | ||
1739 | dprintk("<-- nfs4_create_referral_server() = error %d\n", error); | ||
1740 | return ERR_PTR(error); | ||
1741 | } | ||
1742 | |||
1743 | #endif /* CONFIG_NFS_V4 */ | ||
1744 | |||
1745 | /* | 1098 | /* |
1746 | * Clone an NFS2, NFS3 or NFS4 server record | 1099 | * Clone an NFS2, NFS3 or NFS4 server record |
1747 | */ | 1100 | */ |
@@ -2091,7 +1444,3 @@ void nfs_fs_proc_exit(void) | |||
2091 | } | 1444 | } |
2092 | 1445 | ||
2093 | #endif /* CONFIG_PROC_FS */ | 1446 | #endif /* CONFIG_PROC_FS */ |
2094 | |||
2095 | module_param(nfs4_disable_idmapping, bool, 0644); | ||
2096 | MODULE_PARM_DESC(nfs4_disable_idmapping, | ||
2097 | "Turn off NFSv4 idmapping when using 'sec=sys'"); | ||
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index bd3a9601d32d..81c5eec3cf38 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -47,7 +47,7 @@ void nfs_mark_delegation_referenced(struct nfs_delegation *delegation) | |||
47 | * | 47 | * |
48 | * Returns one if inode has the indicated delegation, otherwise zero. | 48 | * Returns one if inode has the indicated delegation, otherwise zero. |
49 | */ | 49 | */ |
50 | int nfs_have_delegation(struct inode *inode, fmode_t flags) | 50 | int nfs4_have_delegation(struct inode *inode, fmode_t flags) |
51 | { | 51 | { |
52 | struct nfs_delegation *delegation; | 52 | struct nfs_delegation *delegation; |
53 | int ret = 0; | 53 | int ret = 0; |
@@ -388,7 +388,7 @@ void nfs_inode_return_delegation_noreclaim(struct inode *inode) | |||
388 | * | 388 | * |
389 | * Returns zero on success, or a negative errno value. | 389 | * Returns zero on success, or a negative errno value. |
390 | */ | 390 | */ |
391 | int nfs_inode_return_delegation(struct inode *inode) | 391 | int nfs4_inode_return_delegation(struct inode *inode) |
392 | { | 392 | { |
393 | struct nfs_server *server = NFS_SERVER(inode); | 393 | struct nfs_server *server = NFS_SERVER(inode); |
394 | struct nfs_inode *nfsi = NFS_I(inode); | 394 | struct nfs_inode *nfsi = NFS_I(inode); |
@@ -417,9 +417,8 @@ static void nfs_mark_return_delegation(struct nfs_server *server, | |||
417 | * @sb: sb to process | 417 | * @sb: sb to process |
418 | * | 418 | * |
419 | */ | 419 | */ |
420 | void nfs_super_return_all_delegations(struct super_block *sb) | 420 | void nfs_server_return_all_delegations(struct nfs_server *server) |
421 | { | 421 | { |
422 | struct nfs_server *server = NFS_SB(sb); | ||
423 | struct nfs_client *clp = server->nfs_client; | 422 | struct nfs_client *clp = server->nfs_client; |
424 | struct nfs_delegation *delegation; | 423 | struct nfs_delegation *delegation; |
425 | 424 | ||
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index 72709c4193fa..1f3ccd934635 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h | |||
@@ -33,12 +33,12 @@ enum { | |||
33 | 33 | ||
34 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); | 34 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); |
35 | void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); | 35 | void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); |
36 | int nfs_inode_return_delegation(struct inode *inode); | 36 | int nfs4_inode_return_delegation(struct inode *inode); |
37 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid); | 37 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid); |
38 | void nfs_inode_return_delegation_noreclaim(struct inode *inode); | 38 | void nfs_inode_return_delegation_noreclaim(struct inode *inode); |
39 | 39 | ||
40 | struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); | 40 | struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); |
41 | void nfs_super_return_all_delegations(struct super_block *sb); | 41 | void nfs_server_return_all_delegations(struct nfs_server *); |
42 | void nfs_expire_all_delegations(struct nfs_client *clp); | 42 | void nfs_expire_all_delegations(struct nfs_client *clp); |
43 | void nfs_expire_all_delegation_types(struct nfs_client *clp, fmode_t flags); | 43 | void nfs_expire_all_delegation_types(struct nfs_client *clp, fmode_t flags); |
44 | void nfs_expire_unreferenced_delegations(struct nfs_client *clp); | 44 | void nfs_expire_unreferenced_delegations(struct nfs_client *clp); |
@@ -56,24 +56,13 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl); | |||
56 | bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode, fmode_t flags); | 56 | bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode, fmode_t flags); |
57 | 57 | ||
58 | void nfs_mark_delegation_referenced(struct nfs_delegation *delegation); | 58 | void nfs_mark_delegation_referenced(struct nfs_delegation *delegation); |
59 | int nfs_have_delegation(struct inode *inode, fmode_t flags); | 59 | int nfs4_have_delegation(struct inode *inode, fmode_t flags); |
60 | 60 | ||
61 | #else | ||
62 | static inline int nfs_have_delegation(struct inode *inode, fmode_t flags) | ||
63 | { | ||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | static inline int nfs_inode_return_delegation(struct inode *inode) | ||
68 | { | ||
69 | nfs_wb_all(inode); | ||
70 | return 0; | ||
71 | } | ||
72 | #endif | 61 | #endif |
73 | 62 | ||
74 | static inline int nfs_have_delegated_attributes(struct inode *inode) | 63 | static inline int nfs_have_delegated_attributes(struct inode *inode) |
75 | { | 64 | { |
76 | return nfs_have_delegation(inode, FMODE_READ) && | 65 | return NFS_PROTO(inode)->have_delegation(inode, FMODE_READ) && |
77 | !(NFS_I(inode)->cache_validity & NFS_INO_REVAL_FORCED); | 66 | !(NFS_I(inode)->cache_validity & NFS_INO_REVAL_FORCED); |
78 | } | 67 | } |
79 | 68 | ||
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index a6b1c7fb8232..d49f1b9cd3fd 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -46,16 +46,6 @@ | |||
46 | static int nfs_opendir(struct inode *, struct file *); | 46 | static int nfs_opendir(struct inode *, struct file *); |
47 | static int nfs_closedir(struct inode *, struct file *); | 47 | static int nfs_closedir(struct inode *, struct file *); |
48 | static int nfs_readdir(struct file *, void *, filldir_t); | 48 | static int nfs_readdir(struct file *, void *, filldir_t); |
49 | static struct dentry *nfs_lookup(struct inode *, struct dentry *, unsigned int); | ||
50 | static int nfs_create(struct inode *, struct dentry *, umode_t, bool); | ||
51 | static int nfs_mkdir(struct inode *, struct dentry *, umode_t); | ||
52 | static int nfs_rmdir(struct inode *, struct dentry *); | ||
53 | static int nfs_unlink(struct inode *, struct dentry *); | ||
54 | static int nfs_symlink(struct inode *, struct dentry *, const char *); | ||
55 | static int nfs_link(struct dentry *, struct inode *, struct dentry *); | ||
56 | static int nfs_mknod(struct inode *, struct dentry *, umode_t, dev_t); | ||
57 | static int nfs_rename(struct inode *, struct dentry *, | ||
58 | struct inode *, struct dentry *); | ||
59 | static int nfs_fsync_dir(struct file *, loff_t, loff_t, int); | 49 | static int nfs_fsync_dir(struct file *, loff_t, loff_t, int); |
60 | static loff_t nfs_llseek_dir(struct file *, loff_t, int); | 50 | static loff_t nfs_llseek_dir(struct file *, loff_t, int); |
61 | static void nfs_readdir_clear_array(struct page*); | 51 | static void nfs_readdir_clear_array(struct page*); |
@@ -69,73 +59,10 @@ const struct file_operations nfs_dir_operations = { | |||
69 | .fsync = nfs_fsync_dir, | 59 | .fsync = nfs_fsync_dir, |
70 | }; | 60 | }; |
71 | 61 | ||
72 | const struct inode_operations nfs_dir_inode_operations = { | ||
73 | .create = nfs_create, | ||
74 | .lookup = nfs_lookup, | ||
75 | .link = nfs_link, | ||
76 | .unlink = nfs_unlink, | ||
77 | .symlink = nfs_symlink, | ||
78 | .mkdir = nfs_mkdir, | ||
79 | .rmdir = nfs_rmdir, | ||
80 | .mknod = nfs_mknod, | ||
81 | .rename = nfs_rename, | ||
82 | .permission = nfs_permission, | ||
83 | .getattr = nfs_getattr, | ||
84 | .setattr = nfs_setattr, | ||
85 | }; | ||
86 | |||
87 | const struct address_space_operations nfs_dir_aops = { | 62 | const struct address_space_operations nfs_dir_aops = { |
88 | .freepage = nfs_readdir_clear_array, | 63 | .freepage = nfs_readdir_clear_array, |
89 | }; | 64 | }; |
90 | 65 | ||
91 | #ifdef CONFIG_NFS_V3 | ||
92 | const struct inode_operations nfs3_dir_inode_operations = { | ||
93 | .create = nfs_create, | ||
94 | .lookup = nfs_lookup, | ||
95 | .link = nfs_link, | ||
96 | .unlink = nfs_unlink, | ||
97 | .symlink = nfs_symlink, | ||
98 | .mkdir = nfs_mkdir, | ||
99 | .rmdir = nfs_rmdir, | ||
100 | .mknod = nfs_mknod, | ||
101 | .rename = nfs_rename, | ||
102 | .permission = nfs_permission, | ||
103 | .getattr = nfs_getattr, | ||
104 | .setattr = nfs_setattr, | ||
105 | .listxattr = nfs3_listxattr, | ||
106 | .getxattr = nfs3_getxattr, | ||
107 | .setxattr = nfs3_setxattr, | ||
108 | .removexattr = nfs3_removexattr, | ||
109 | }; | ||
110 | #endif /* CONFIG_NFS_V3 */ | ||
111 | |||
112 | #ifdef CONFIG_NFS_V4 | ||
113 | |||
114 | static int nfs_atomic_open(struct inode *, struct dentry *, | ||
115 | struct file *, unsigned, umode_t, | ||
116 | int *); | ||
117 | const struct inode_operations nfs4_dir_inode_operations = { | ||
118 | .create = nfs_create, | ||
119 | .lookup = nfs_lookup, | ||
120 | .atomic_open = nfs_atomic_open, | ||
121 | .link = nfs_link, | ||
122 | .unlink = nfs_unlink, | ||
123 | .symlink = nfs_symlink, | ||
124 | .mkdir = nfs_mkdir, | ||
125 | .rmdir = nfs_rmdir, | ||
126 | .mknod = nfs_mknod, | ||
127 | .rename = nfs_rename, | ||
128 | .permission = nfs_permission, | ||
129 | .getattr = nfs_getattr, | ||
130 | .setattr = nfs_setattr, | ||
131 | .getxattr = generic_getxattr, | ||
132 | .setxattr = generic_setxattr, | ||
133 | .listxattr = generic_listxattr, | ||
134 | .removexattr = generic_removexattr, | ||
135 | }; | ||
136 | |||
137 | #endif /* CONFIG_NFS_V4 */ | ||
138 | |||
139 | static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir, struct rpc_cred *cred) | 66 | static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir, struct rpc_cred *cred) |
140 | { | 67 | { |
141 | struct nfs_open_dir_context *ctx; | 68 | struct nfs_open_dir_context *ctx; |
@@ -1128,7 +1055,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags) | |||
1128 | goto out_bad; | 1055 | goto out_bad; |
1129 | } | 1056 | } |
1130 | 1057 | ||
1131 | if (nfs_have_delegation(inode, FMODE_READ)) | 1058 | if (NFS_PROTO(dir)->have_delegation(inode, FMODE_READ)) |
1132 | goto out_set_verifier; | 1059 | goto out_set_verifier; |
1133 | 1060 | ||
1134 | /* Force a full look up iff the parent directory has changed */ | 1061 | /* Force a full look up iff the parent directory has changed */ |
@@ -1270,7 +1197,7 @@ const struct dentry_operations nfs_dentry_operations = { | |||
1270 | .d_release = nfs_d_release, | 1197 | .d_release = nfs_d_release, |
1271 | }; | 1198 | }; |
1272 | 1199 | ||
1273 | static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags) | 1200 | struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags) |
1274 | { | 1201 | { |
1275 | struct dentry *res; | 1202 | struct dentry *res; |
1276 | struct dentry *parent; | 1203 | struct dentry *parent; |
@@ -1398,9 +1325,9 @@ out: | |||
1398 | return err; | 1325 | return err; |
1399 | } | 1326 | } |
1400 | 1327 | ||
1401 | static int nfs_atomic_open(struct inode *dir, struct dentry *dentry, | 1328 | int nfs_atomic_open(struct inode *dir, struct dentry *dentry, |
1402 | struct file *file, unsigned open_flags, | 1329 | struct file *file, unsigned open_flags, |
1403 | umode_t mode, int *opened) | 1330 | umode_t mode, int *opened) |
1404 | { | 1331 | { |
1405 | struct nfs_open_context *ctx; | 1332 | struct nfs_open_context *ctx; |
1406 | struct dentry *res; | 1333 | struct dentry *res; |
@@ -1588,7 +1515,7 @@ out_error: | |||
1588 | * that the operation succeeded on the server, but an error in the | 1515 | * that the operation succeeded on the server, but an error in the |
1589 | * reply path made it appear to have failed. | 1516 | * reply path made it appear to have failed. |
1590 | */ | 1517 | */ |
1591 | static int nfs_create(struct inode *dir, struct dentry *dentry, | 1518 | int nfs_create(struct inode *dir, struct dentry *dentry, |
1592 | umode_t mode, bool excl) | 1519 | umode_t mode, bool excl) |
1593 | { | 1520 | { |
1594 | struct iattr attr; | 1521 | struct iattr attr; |
@@ -1613,7 +1540,7 @@ out_err: | |||
1613 | /* | 1540 | /* |
1614 | * See comments for nfs_proc_create regarding failed operations. | 1541 | * See comments for nfs_proc_create regarding failed operations. |
1615 | */ | 1542 | */ |
1616 | static int | 1543 | int |
1617 | nfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) | 1544 | nfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) |
1618 | { | 1545 | { |
1619 | struct iattr attr; | 1546 | struct iattr attr; |
@@ -1640,7 +1567,7 @@ out_err: | |||
1640 | /* | 1567 | /* |
1641 | * See comments for nfs_proc_create regarding failed operations. | 1568 | * See comments for nfs_proc_create regarding failed operations. |
1642 | */ | 1569 | */ |
1643 | static int nfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | 1570 | int nfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) |
1644 | { | 1571 | { |
1645 | struct iattr attr; | 1572 | struct iattr attr; |
1646 | int error; | 1573 | int error; |
@@ -1666,7 +1593,7 @@ static void nfs_dentry_handle_enoent(struct dentry *dentry) | |||
1666 | d_delete(dentry); | 1593 | d_delete(dentry); |
1667 | } | 1594 | } |
1668 | 1595 | ||
1669 | static int nfs_rmdir(struct inode *dir, struct dentry *dentry) | 1596 | int nfs_rmdir(struct inode *dir, struct dentry *dentry) |
1670 | { | 1597 | { |
1671 | int error; | 1598 | int error; |
1672 | 1599 | ||
@@ -1706,7 +1633,7 @@ static int nfs_safe_remove(struct dentry *dentry) | |||
1706 | } | 1633 | } |
1707 | 1634 | ||
1708 | if (inode != NULL) { | 1635 | if (inode != NULL) { |
1709 | nfs_inode_return_delegation(inode); | 1636 | NFS_PROTO(inode)->return_delegation(inode); |
1710 | error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); | 1637 | error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); |
1711 | /* The VFS may want to delete this inode */ | 1638 | /* The VFS may want to delete this inode */ |
1712 | if (error == 0) | 1639 | if (error == 0) |
@@ -1725,7 +1652,7 @@ out: | |||
1725 | * | 1652 | * |
1726 | * If sillyrename() returns 0, we do nothing, otherwise we unlink. | 1653 | * If sillyrename() returns 0, we do nothing, otherwise we unlink. |
1727 | */ | 1654 | */ |
1728 | static int nfs_unlink(struct inode *dir, struct dentry *dentry) | 1655 | int nfs_unlink(struct inode *dir, struct dentry *dentry) |
1729 | { | 1656 | { |
1730 | int error; | 1657 | int error; |
1731 | int need_rehash = 0; | 1658 | int need_rehash = 0; |
@@ -1769,7 +1696,7 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry) | |||
1769 | * now have a new file handle and can instantiate an in-core NFS inode | 1696 | * now have a new file handle and can instantiate an in-core NFS inode |
1770 | * and move the raw page into its mapping. | 1697 | * and move the raw page into its mapping. |
1771 | */ | 1698 | */ |
1772 | static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) | 1699 | int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) |
1773 | { | 1700 | { |
1774 | struct pagevec lru_pvec; | 1701 | struct pagevec lru_pvec; |
1775 | struct page *page; | 1702 | struct page *page; |
@@ -1824,7 +1751,7 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym | |||
1824 | return 0; | 1751 | return 0; |
1825 | } | 1752 | } |
1826 | 1753 | ||
1827 | static int | 1754 | int |
1828 | nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) | 1755 | nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) |
1829 | { | 1756 | { |
1830 | struct inode *inode = old_dentry->d_inode; | 1757 | struct inode *inode = old_dentry->d_inode; |
@@ -1834,7 +1761,7 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) | |||
1834 | old_dentry->d_parent->d_name.name, old_dentry->d_name.name, | 1761 | old_dentry->d_parent->d_name.name, old_dentry->d_name.name, |
1835 | dentry->d_parent->d_name.name, dentry->d_name.name); | 1762 | dentry->d_parent->d_name.name, dentry->d_name.name); |
1836 | 1763 | ||
1837 | nfs_inode_return_delegation(inode); | 1764 | NFS_PROTO(inode)->return_delegation(inode); |
1838 | 1765 | ||
1839 | d_drop(dentry); | 1766 | d_drop(dentry); |
1840 | error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name); | 1767 | error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name); |
@@ -1869,7 +1796,7 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) | |||
1869 | * If these conditions are met, we can drop the dentries before doing | 1796 | * If these conditions are met, we can drop the dentries before doing |
1870 | * the rename. | 1797 | * the rename. |
1871 | */ | 1798 | */ |
1872 | static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, | 1799 | int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, |
1873 | struct inode *new_dir, struct dentry *new_dentry) | 1800 | struct inode *new_dir, struct dentry *new_dentry) |
1874 | { | 1801 | { |
1875 | struct inode *old_inode = old_dentry->d_inode; | 1802 | struct inode *old_inode = old_dentry->d_inode; |
@@ -1918,9 +1845,9 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1918 | } | 1845 | } |
1919 | } | 1846 | } |
1920 | 1847 | ||
1921 | nfs_inode_return_delegation(old_inode); | 1848 | NFS_PROTO(old_inode)->return_delegation(old_inode); |
1922 | if (new_inode != NULL) | 1849 | if (new_inode != NULL) |
1923 | nfs_inode_return_delegation(new_inode); | 1850 | NFS_PROTO(new_inode)->return_delegation(new_inode); |
1924 | 1851 | ||
1925 | error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name, | 1852 | error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name, |
1926 | new_dir, &new_dentry->d_name); | 1853 | new_dir, &new_dentry->d_name); |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 48253372ab1d..42dce909ec70 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -393,7 +393,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, | |||
393 | size_t requested_bytes = 0; | 393 | size_t requested_bytes = 0; |
394 | unsigned long seg; | 394 | unsigned long seg; |
395 | 395 | ||
396 | nfs_pageio_init_read(&desc, dreq->inode, | 396 | NFS_PROTO(dreq->inode)->read_pageio_init(&desc, dreq->inode, |
397 | &nfs_direct_read_completion_ops); | 397 | &nfs_direct_read_completion_ops); |
398 | get_dreq(dreq); | 398 | get_dreq(dreq); |
399 | desc.pg_dreq = dreq; | 399 | desc.pg_dreq = dreq; |
@@ -478,7 +478,7 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) | |||
478 | dreq->count = 0; | 478 | dreq->count = 0; |
479 | get_dreq(dreq); | 479 | get_dreq(dreq); |
480 | 480 | ||
481 | nfs_pageio_init_write(&desc, dreq->inode, FLUSH_STABLE, | 481 | NFS_PROTO(dreq->inode)->write_pageio_init(&desc, dreq->inode, FLUSH_STABLE, |
482 | &nfs_direct_write_completion_ops); | 482 | &nfs_direct_write_completion_ops); |
483 | desc.pg_dreq = dreq; | 483 | desc.pg_dreq = dreq; |
484 | 484 | ||
@@ -782,7 +782,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, | |||
782 | size_t requested_bytes = 0; | 782 | size_t requested_bytes = 0; |
783 | unsigned long seg; | 783 | unsigned long seg; |
784 | 784 | ||
785 | nfs_pageio_init_write(&desc, inode, FLUSH_COND_STABLE, | 785 | NFS_PROTO(inode)->write_pageio_init(&desc, inode, FLUSH_COND_STABLE, |
786 | &nfs_direct_write_completion_ops); | 786 | &nfs_direct_write_completion_ops); |
787 | desc.pg_dreq = dreq; | 787 | desc.pg_dreq = dreq; |
788 | get_dreq(dreq); | 788 | get_dreq(dreq); |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index a6708e6b438d..70d124a61b98 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -35,36 +35,17 @@ | |||
35 | #include "internal.h" | 35 | #include "internal.h" |
36 | #include "iostat.h" | 36 | #include "iostat.h" |
37 | #include "fscache.h" | 37 | #include "fscache.h" |
38 | #include "pnfs.h" | ||
39 | 38 | ||
40 | #define NFSDBG_FACILITY NFSDBG_FILE | 39 | #define NFSDBG_FACILITY NFSDBG_FILE |
41 | 40 | ||
42 | static const struct vm_operations_struct nfs_file_vm_ops; | 41 | static const struct vm_operations_struct nfs_file_vm_ops; |
43 | 42 | ||
44 | const struct inode_operations nfs_file_inode_operations = { | ||
45 | .permission = nfs_permission, | ||
46 | .getattr = nfs_getattr, | ||
47 | .setattr = nfs_setattr, | ||
48 | }; | ||
49 | |||
50 | #ifdef CONFIG_NFS_V3 | ||
51 | const struct inode_operations nfs3_file_inode_operations = { | ||
52 | .permission = nfs_permission, | ||
53 | .getattr = nfs_getattr, | ||
54 | .setattr = nfs_setattr, | ||
55 | .listxattr = nfs3_listxattr, | ||
56 | .getxattr = nfs3_getxattr, | ||
57 | .setxattr = nfs3_setxattr, | ||
58 | .removexattr = nfs3_removexattr, | ||
59 | }; | ||
60 | #endif /* CONFIG_NFS_v3 */ | ||
61 | |||
62 | /* Hack for future NFS swap support */ | 43 | /* Hack for future NFS swap support */ |
63 | #ifndef IS_SWAPFILE | 44 | #ifndef IS_SWAPFILE |
64 | # define IS_SWAPFILE(inode) (0) | 45 | # define IS_SWAPFILE(inode) (0) |
65 | #endif | 46 | #endif |
66 | 47 | ||
67 | static int nfs_check_flags(int flags) | 48 | int nfs_check_flags(int flags) |
68 | { | 49 | { |
69 | if ((flags & (O_APPEND | O_DIRECT)) == (O_APPEND | O_DIRECT)) | 50 | if ((flags & (O_APPEND | O_DIRECT)) == (O_APPEND | O_DIRECT)) |
70 | return -EINVAL; | 51 | return -EINVAL; |
@@ -93,7 +74,7 @@ nfs_file_open(struct inode *inode, struct file *filp) | |||
93 | return res; | 74 | return res; |
94 | } | 75 | } |
95 | 76 | ||
96 | static int | 77 | int |
97 | nfs_file_release(struct inode *inode, struct file *filp) | 78 | nfs_file_release(struct inode *inode, struct file *filp) |
98 | { | 79 | { |
99 | dprintk("NFS: release(%s/%s)\n", | 80 | dprintk("NFS: release(%s/%s)\n", |
@@ -135,7 +116,7 @@ force_reval: | |||
135 | return __nfs_revalidate_inode(server, inode); | 116 | return __nfs_revalidate_inode(server, inode); |
136 | } | 117 | } |
137 | 118 | ||
138 | static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin) | 119 | loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin) |
139 | { | 120 | { |
140 | dprintk("NFS: llseek file(%s/%s, %lld, %d)\n", | 121 | dprintk("NFS: llseek file(%s/%s, %lld, %d)\n", |
141 | filp->f_path.dentry->d_parent->d_name.name, | 122 | filp->f_path.dentry->d_parent->d_name.name, |
@@ -160,7 +141,7 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin) | |||
160 | /* | 141 | /* |
161 | * Flush all dirty pages, and check for write errors. | 142 | * Flush all dirty pages, and check for write errors. |
162 | */ | 143 | */ |
163 | static int | 144 | int |
164 | nfs_file_flush(struct file *file, fl_owner_t id) | 145 | nfs_file_flush(struct file *file, fl_owner_t id) |
165 | { | 146 | { |
166 | struct dentry *dentry = file->f_path.dentry; | 147 | struct dentry *dentry = file->f_path.dentry; |
@@ -178,14 +159,14 @@ nfs_file_flush(struct file *file, fl_owner_t id) | |||
178 | * If we're holding a write delegation, then just start the i/o | 159 | * If we're holding a write delegation, then just start the i/o |
179 | * but don't wait for completion (or send a commit). | 160 | * but don't wait for completion (or send a commit). |
180 | */ | 161 | */ |
181 | if (nfs_have_delegation(inode, FMODE_WRITE)) | 162 | if (NFS_PROTO(inode)->have_delegation(inode, FMODE_WRITE)) |
182 | return filemap_fdatawrite(file->f_mapping); | 163 | return filemap_fdatawrite(file->f_mapping); |
183 | 164 | ||
184 | /* Flush writes to the server and return any errors */ | 165 | /* Flush writes to the server and return any errors */ |
185 | return vfs_fsync(file, 0); | 166 | return vfs_fsync(file, 0); |
186 | } | 167 | } |
187 | 168 | ||
188 | static ssize_t | 169 | ssize_t |
189 | nfs_file_read(struct kiocb *iocb, const struct iovec *iov, | 170 | nfs_file_read(struct kiocb *iocb, const struct iovec *iov, |
190 | unsigned long nr_segs, loff_t pos) | 171 | unsigned long nr_segs, loff_t pos) |
191 | { | 172 | { |
@@ -209,7 +190,7 @@ nfs_file_read(struct kiocb *iocb, const struct iovec *iov, | |||
209 | return result; | 190 | return result; |
210 | } | 191 | } |
211 | 192 | ||
212 | static ssize_t | 193 | ssize_t |
213 | nfs_file_splice_read(struct file *filp, loff_t *ppos, | 194 | nfs_file_splice_read(struct file *filp, loff_t *ppos, |
214 | struct pipe_inode_info *pipe, size_t count, | 195 | struct pipe_inode_info *pipe, size_t count, |
215 | unsigned int flags) | 196 | unsigned int flags) |
@@ -231,7 +212,7 @@ nfs_file_splice_read(struct file *filp, loff_t *ppos, | |||
231 | return res; | 212 | return res; |
232 | } | 213 | } |
233 | 214 | ||
234 | static int | 215 | int |
235 | nfs_file_mmap(struct file * file, struct vm_area_struct * vma) | 216 | nfs_file_mmap(struct file * file, struct vm_area_struct * vma) |
236 | { | 217 | { |
237 | struct dentry *dentry = file->f_path.dentry; | 218 | struct dentry *dentry = file->f_path.dentry; |
@@ -264,8 +245,8 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma) | |||
264 | * nfs_file_write() that a write error occurred, and hence cause it to | 245 | * nfs_file_write() that a write error occurred, and hence cause it to |
265 | * fall back to doing a synchronous write. | 246 | * fall back to doing a synchronous write. |
266 | */ | 247 | */ |
267 | static int | 248 | int |
268 | nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) | 249 | nfs_file_fsync_commit(struct file *file, loff_t start, loff_t end, int datasync) |
269 | { | 250 | { |
270 | struct dentry *dentry = file->f_path.dentry; | 251 | struct dentry *dentry = file->f_path.dentry; |
271 | struct nfs_open_context *ctx = nfs_file_open_context(file); | 252 | struct nfs_open_context *ctx = nfs_file_open_context(file); |
@@ -277,9 +258,6 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) | |||
277 | dentry->d_parent->d_name.name, dentry->d_name.name, | 258 | dentry->d_parent->d_name.name, dentry->d_name.name, |
278 | datasync); | 259 | datasync); |
279 | 260 | ||
280 | ret = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
281 | mutex_lock(&inode->i_mutex); | ||
282 | |||
283 | nfs_inc_stats(inode, NFSIOS_VFSFSYNC); | 261 | nfs_inc_stats(inode, NFSIOS_VFSFSYNC); |
284 | have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); | 262 | have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); |
285 | status = nfs_commit_inode(inode, FLUSH_SYNC); | 263 | status = nfs_commit_inode(inode, FLUSH_SYNC); |
@@ -290,10 +268,20 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) | |||
290 | ret = xchg(&ctx->error, 0); | 268 | ret = xchg(&ctx->error, 0); |
291 | if (!ret && status < 0) | 269 | if (!ret && status < 0) |
292 | ret = status; | 270 | ret = status; |
293 | if (!ret && !datasync) | 271 | return ret; |
294 | /* application has asked for meta-data sync */ | 272 | } |
295 | ret = pnfs_layoutcommit_inode(inode, true); | 273 | |
274 | static int | ||
275 | nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) | ||
276 | { | ||
277 | int ret; | ||
278 | struct inode *inode = file->f_path.dentry->d_inode; | ||
279 | |||
280 | ret = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
281 | mutex_lock(&inode->i_mutex); | ||
282 | ret = nfs_file_fsync_commit(file, start, end, datasync); | ||
296 | mutex_unlock(&inode->i_mutex); | 283 | mutex_unlock(&inode->i_mutex); |
284 | |||
297 | return ret; | 285 | return ret; |
298 | } | 286 | } |
299 | 287 | ||
@@ -572,8 +560,8 @@ static int nfs_need_sync_write(struct file *filp, struct inode *inode) | |||
572 | return 0; | 560 | return 0; |
573 | } | 561 | } |
574 | 562 | ||
575 | static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, | 563 | ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, |
576 | unsigned long nr_segs, loff_t pos) | 564 | unsigned long nr_segs, loff_t pos) |
577 | { | 565 | { |
578 | struct dentry * dentry = iocb->ki_filp->f_path.dentry; | 566 | struct dentry * dentry = iocb->ki_filp->f_path.dentry; |
579 | struct inode * inode = dentry->d_inode; | 567 | struct inode * inode = dentry->d_inode; |
@@ -624,9 +612,9 @@ out_swapfile: | |||
624 | goto out; | 612 | goto out; |
625 | } | 613 | } |
626 | 614 | ||
627 | static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe, | 615 | ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe, |
628 | struct file *filp, loff_t *ppos, | 616 | struct file *filp, loff_t *ppos, |
629 | size_t count, unsigned int flags) | 617 | size_t count, unsigned int flags) |
630 | { | 618 | { |
631 | struct dentry *dentry = filp->f_path.dentry; | 619 | struct dentry *dentry = filp->f_path.dentry; |
632 | struct inode *inode = dentry->d_inode; | 620 | struct inode *inode = dentry->d_inode; |
@@ -670,7 +658,7 @@ do_getlk(struct file *filp, int cmd, struct file_lock *fl, int is_local) | |||
670 | } | 658 | } |
671 | fl->fl_type = saved_type; | 659 | fl->fl_type = saved_type; |
672 | 660 | ||
673 | if (nfs_have_delegation(inode, FMODE_READ)) | 661 | if (NFS_PROTO(inode)->have_delegation(inode, FMODE_READ)) |
674 | goto out_noconflict; | 662 | goto out_noconflict; |
675 | 663 | ||
676 | if (is_local) | 664 | if (is_local) |
@@ -765,7 +753,7 @@ do_setlk(struct file *filp, int cmd, struct file_lock *fl, int is_local) | |||
765 | * This makes locking act as a cache coherency point. | 753 | * This makes locking act as a cache coherency point. |
766 | */ | 754 | */ |
767 | nfs_sync_mapping(filp->f_mapping); | 755 | nfs_sync_mapping(filp->f_mapping); |
768 | if (!nfs_have_delegation(inode, FMODE_READ)) { | 756 | if (!NFS_PROTO(inode)->have_delegation(inode, FMODE_READ)) { |
769 | if (is_time_granular(&NFS_SERVER(inode)->time_delta)) | 757 | if (is_time_granular(&NFS_SERVER(inode)->time_delta)) |
770 | __nfs_revalidate_inode(NFS_SERVER(inode), inode); | 758 | __nfs_revalidate_inode(NFS_SERVER(inode), inode); |
771 | else | 759 | else |
@@ -778,7 +766,7 @@ out: | |||
778 | /* | 766 | /* |
779 | * Lock a (portion of) a file | 767 | * Lock a (portion of) a file |
780 | */ | 768 | */ |
781 | static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl) | 769 | int nfs_lock(struct file *filp, int cmd, struct file_lock *fl) |
782 | { | 770 | { |
783 | struct inode *inode = filp->f_mapping->host; | 771 | struct inode *inode = filp->f_mapping->host; |
784 | int ret = -ENOLCK; | 772 | int ret = -ENOLCK; |
@@ -818,7 +806,7 @@ out_err: | |||
818 | /* | 806 | /* |
819 | * Lock a (portion of) a file | 807 | * Lock a (portion of) a file |
820 | */ | 808 | */ |
821 | static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl) | 809 | int nfs_flock(struct file *filp, int cmd, struct file_lock *fl) |
822 | { | 810 | { |
823 | struct inode *inode = filp->f_mapping->host; | 811 | struct inode *inode = filp->f_mapping->host; |
824 | int is_local = 0; | 812 | int is_local = 0; |
@@ -848,7 +836,7 @@ static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl) | |||
848 | * There is no protocol support for leases, so we have no way to implement | 836 | * There is no protocol support for leases, so we have no way to implement |
849 | * them correctly in the face of opens by other clients. | 837 | * them correctly in the face of opens by other clients. |
850 | */ | 838 | */ |
851 | static int nfs_setlease(struct file *file, long arg, struct file_lock **fl) | 839 | int nfs_setlease(struct file *file, long arg, struct file_lock **fl) |
852 | { | 840 | { |
853 | dprintk("NFS: setlease(%s/%s, arg=%ld)\n", | 841 | dprintk("NFS: setlease(%s/%s, arg=%ld)\n", |
854 | file->f_path.dentry->d_parent->d_name.name, | 842 | file->f_path.dentry->d_parent->d_name.name, |
@@ -874,104 +862,3 @@ const struct file_operations nfs_file_operations = { | |||
874 | .check_flags = nfs_check_flags, | 862 | .check_flags = nfs_check_flags, |
875 | .setlease = nfs_setlease, | 863 | .setlease = nfs_setlease, |
876 | }; | 864 | }; |
877 | |||
878 | #ifdef CONFIG_NFS_V4 | ||
879 | static int | ||
880 | nfs4_file_open(struct inode *inode, struct file *filp) | ||
881 | { | ||
882 | struct nfs_open_context *ctx; | ||
883 | struct dentry *dentry = filp->f_path.dentry; | ||
884 | struct dentry *parent = NULL; | ||
885 | struct inode *dir; | ||
886 | unsigned openflags = filp->f_flags; | ||
887 | struct iattr attr; | ||
888 | int err; | ||
889 | |||
890 | BUG_ON(inode != dentry->d_inode); | ||
891 | /* | ||
892 | * If no cached dentry exists or if it's negative, NFSv4 handled the | ||
893 | * opens in ->lookup() or ->create(). | ||
894 | * | ||
895 | * We only get this far for a cached positive dentry. We skipped | ||
896 | * revalidation, so handle it here by dropping the dentry and returning | ||
897 | * -EOPENSTALE. The VFS will retry the lookup/create/open. | ||
898 | */ | ||
899 | |||
900 | dprintk("NFS: open file(%s/%s)\n", | ||
901 | dentry->d_parent->d_name.name, | ||
902 | dentry->d_name.name); | ||
903 | |||
904 | if ((openflags & O_ACCMODE) == 3) | ||
905 | openflags--; | ||
906 | |||
907 | /* We can't create new files here */ | ||
908 | openflags &= ~(O_CREAT|O_EXCL); | ||
909 | |||
910 | parent = dget_parent(dentry); | ||
911 | dir = parent->d_inode; | ||
912 | |||
913 | ctx = alloc_nfs_open_context(filp->f_path.dentry, filp->f_mode); | ||
914 | err = PTR_ERR(ctx); | ||
915 | if (IS_ERR(ctx)) | ||
916 | goto out; | ||
917 | |||
918 | attr.ia_valid = ATTR_OPEN; | ||
919 | if (openflags & O_TRUNC) { | ||
920 | attr.ia_valid |= ATTR_SIZE; | ||
921 | attr.ia_size = 0; | ||
922 | nfs_wb_all(inode); | ||
923 | } | ||
924 | |||
925 | inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr); | ||
926 | if (IS_ERR(inode)) { | ||
927 | err = PTR_ERR(inode); | ||
928 | switch (err) { | ||
929 | case -EPERM: | ||
930 | case -EACCES: | ||
931 | case -EDQUOT: | ||
932 | case -ENOSPC: | ||
933 | case -EROFS: | ||
934 | goto out_put_ctx; | ||
935 | default: | ||
936 | goto out_drop; | ||
937 | } | ||
938 | } | ||
939 | iput(inode); | ||
940 | if (inode != dentry->d_inode) | ||
941 | goto out_drop; | ||
942 | |||
943 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | ||
944 | nfs_file_set_open_context(filp, ctx); | ||
945 | err = 0; | ||
946 | |||
947 | out_put_ctx: | ||
948 | put_nfs_open_context(ctx); | ||
949 | out: | ||
950 | dput(parent); | ||
951 | return err; | ||
952 | |||
953 | out_drop: | ||
954 | d_drop(dentry); | ||
955 | err = -EOPENSTALE; | ||
956 | goto out_put_ctx; | ||
957 | } | ||
958 | |||
959 | const struct file_operations nfs4_file_operations = { | ||
960 | .llseek = nfs_file_llseek, | ||
961 | .read = do_sync_read, | ||
962 | .write = do_sync_write, | ||
963 | .aio_read = nfs_file_read, | ||
964 | .aio_write = nfs_file_write, | ||
965 | .mmap = nfs_file_mmap, | ||
966 | .open = nfs4_file_open, | ||
967 | .flush = nfs_file_flush, | ||
968 | .release = nfs_file_release, | ||
969 | .fsync = nfs_file_fsync, | ||
970 | .lock = nfs_lock, | ||
971 | .flock = nfs_flock, | ||
972 | .splice_read = nfs_file_splice_read, | ||
973 | .splice_write = nfs_file_splice_write, | ||
974 | .check_flags = nfs_check_flags, | ||
975 | .setlease = nfs_setlease, | ||
976 | }; | ||
977 | #endif /* CONFIG_NFS_V4 */ | ||
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index a67990f90bd7..4654ced096a6 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c | |||
@@ -23,21 +23,15 @@ | |||
23 | #include <linux/sunrpc/stats.h> | 23 | #include <linux/sunrpc/stats.h> |
24 | #include <linux/nfs_fs.h> | 24 | #include <linux/nfs_fs.h> |
25 | #include <linux/nfs_mount.h> | 25 | #include <linux/nfs_mount.h> |
26 | #include <linux/nfs4_mount.h> | ||
27 | #include <linux/lockd/bind.h> | 26 | #include <linux/lockd/bind.h> |
28 | #include <linux/seq_file.h> | 27 | #include <linux/seq_file.h> |
29 | #include <linux/mount.h> | 28 | #include <linux/mount.h> |
30 | #include <linux/nfs_idmap.h> | ||
31 | #include <linux/vfs.h> | 29 | #include <linux/vfs.h> |
32 | #include <linux/namei.h> | 30 | #include <linux/namei.h> |
33 | #include <linux/security.h> | 31 | #include <linux/security.h> |
34 | 32 | ||
35 | #include <asm/uaccess.h> | 33 | #include <asm/uaccess.h> |
36 | 34 | ||
37 | #include "nfs4_fs.h" | ||
38 | #include "delegation.h" | ||
39 | #include "internal.h" | ||
40 | |||
41 | #define NFSDBG_FACILITY NFSDBG_CLIENT | 35 | #define NFSDBG_FACILITY NFSDBG_CLIENT |
42 | 36 | ||
43 | /* | 37 | /* |
@@ -135,47 +129,3 @@ out: | |||
135 | nfs_free_fattr(fsinfo.fattr); | 129 | nfs_free_fattr(fsinfo.fattr); |
136 | return ret; | 130 | return ret; |
137 | } | 131 | } |
138 | |||
139 | #ifdef CONFIG_NFS_V4 | ||
140 | |||
141 | int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh) | ||
142 | { | ||
143 | struct nfs_fsinfo fsinfo; | ||
144 | int ret = -ENOMEM; | ||
145 | |||
146 | dprintk("--> nfs4_get_rootfh()\n"); | ||
147 | |||
148 | fsinfo.fattr = nfs_alloc_fattr(); | ||
149 | if (fsinfo.fattr == NULL) | ||
150 | goto out; | ||
151 | |||
152 | /* Start by getting the root filehandle from the server */ | ||
153 | ret = nfs4_proc_get_rootfh(server, mntfh, &fsinfo); | ||
154 | if (ret < 0) { | ||
155 | dprintk("nfs4_get_rootfh: getroot error = %d\n", -ret); | ||
156 | goto out; | ||
157 | } | ||
158 | |||
159 | if (!(fsinfo.fattr->valid & NFS_ATTR_FATTR_TYPE) | ||
160 | || !S_ISDIR(fsinfo.fattr->mode)) { | ||
161 | printk(KERN_ERR "nfs4_get_rootfh:" | ||
162 | " getroot encountered non-directory\n"); | ||
163 | ret = -ENOTDIR; | ||
164 | goto out; | ||
165 | } | ||
166 | |||
167 | if (fsinfo.fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) { | ||
168 | printk(KERN_ERR "nfs4_get_rootfh:" | ||
169 | " getroot obtained referral\n"); | ||
170 | ret = -EREMOTE; | ||
171 | goto out; | ||
172 | } | ||
173 | |||
174 | memcpy(&server->fsid, &fsinfo.fattr->fsid, sizeof(server->fsid)); | ||
175 | out: | ||
176 | nfs_free_fattr(fsinfo.fattr); | ||
177 | dprintk("<-- nfs4_get_rootfh() = %d\n", ret); | ||
178 | return ret; | ||
179 | } | ||
180 | |||
181 | #endif /* CONFIG_NFS_V4 */ | ||
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index f7296983eba6..35f7e4bc680e 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -32,7 +32,6 @@ | |||
32 | #include <linux/lockd/bind.h> | 32 | #include <linux/lockd/bind.h> |
33 | #include <linux/seq_file.h> | 33 | #include <linux/seq_file.h> |
34 | #include <linux/mount.h> | 34 | #include <linux/mount.h> |
35 | #include <linux/nfs_idmap.h> | ||
36 | #include <linux/vfs.h> | 35 | #include <linux/vfs.h> |
37 | #include <linux/inet.h> | 36 | #include <linux/inet.h> |
38 | #include <linux/nfs_xdr.h> | 37 | #include <linux/nfs_xdr.h> |
@@ -430,7 +429,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
430 | * Return any delegations if we're going to change ACLs | 429 | * Return any delegations if we're going to change ACLs |
431 | */ | 430 | */ |
432 | if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) | 431 | if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) |
433 | nfs_inode_return_delegation(inode); | 432 | NFS_PROTO(inode)->return_delegation(inode); |
434 | error = NFS_PROTO(inode)->setattr(dentry, fattr, attr); | 433 | error = NFS_PROTO(inode)->setattr(dentry, fattr, attr); |
435 | if (error == 0) | 434 | if (error == 0) |
436 | nfs_refresh_inode(inode, fattr); | 435 | nfs_refresh_inode(inode, fattr); |
@@ -1457,7 +1456,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1457 | if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) | 1456 | if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) |
1458 | || S_ISLNK(inode->i_mode))) | 1457 | || S_ISLNK(inode->i_mode))) |
1459 | invalid &= ~NFS_INO_INVALID_DATA; | 1458 | invalid &= ~NFS_INO_INVALID_DATA; |
1460 | if (!nfs_have_delegation(inode, FMODE_READ) || | 1459 | if (!NFS_PROTO(inode)->have_delegation(inode, FMODE_READ) || |
1461 | (save_cache_validity & NFS_INO_REVAL_FORCED)) | 1460 | (save_cache_validity & NFS_INO_REVAL_FORCED)) |
1462 | nfsi->cache_validity |= invalid; | 1461 | nfsi->cache_validity |= invalid; |
1463 | 1462 | ||
@@ -1628,87 +1627,96 @@ static int __init init_nfs_fs(void) | |||
1628 | { | 1627 | { |
1629 | int err; | 1628 | int err; |
1630 | 1629 | ||
1631 | err = nfs_idmap_init(); | ||
1632 | if (err < 0) | ||
1633 | goto out10; | ||
1634 | |||
1635 | err = nfs_dns_resolver_init(); | 1630 | err = nfs_dns_resolver_init(); |
1636 | if (err < 0) | 1631 | if (err < 0) |
1637 | goto out9; | 1632 | goto out11; |
1638 | 1633 | ||
1639 | err = register_pernet_subsys(&nfs_net_ops); | 1634 | err = register_pernet_subsys(&nfs_net_ops); |
1640 | if (err < 0) | 1635 | if (err < 0) |
1641 | goto out8; | 1636 | goto out10; |
1642 | 1637 | ||
1643 | err = nfs_fscache_register(); | 1638 | err = nfs_fscache_register(); |
1644 | if (err < 0) | 1639 | if (err < 0) |
1645 | goto out7; | 1640 | goto out9; |
1646 | 1641 | ||
1647 | err = nfsiod_start(); | 1642 | err = nfsiod_start(); |
1648 | if (err) | 1643 | if (err) |
1649 | goto out6; | 1644 | goto out8; |
1650 | 1645 | ||
1651 | err = nfs_fs_proc_init(); | 1646 | err = nfs_fs_proc_init(); |
1652 | if (err) | 1647 | if (err) |
1653 | goto out5; | 1648 | goto out7; |
1654 | 1649 | ||
1655 | err = nfs_init_nfspagecache(); | 1650 | err = nfs_init_nfspagecache(); |
1656 | if (err) | 1651 | if (err) |
1657 | goto out4; | 1652 | goto out6; |
1658 | 1653 | ||
1659 | err = nfs_init_inodecache(); | 1654 | err = nfs_init_inodecache(); |
1660 | if (err) | 1655 | if (err) |
1661 | goto out3; | 1656 | goto out5; |
1662 | 1657 | ||
1663 | err = nfs_init_readpagecache(); | 1658 | err = nfs_init_readpagecache(); |
1664 | if (err) | 1659 | if (err) |
1665 | goto out2; | 1660 | goto out4; |
1666 | 1661 | ||
1667 | err = nfs_init_writepagecache(); | 1662 | err = nfs_init_writepagecache(); |
1668 | if (err) | 1663 | if (err) |
1669 | goto out1; | 1664 | goto out3; |
1670 | 1665 | ||
1671 | err = nfs_init_directcache(); | 1666 | err = nfs_init_directcache(); |
1672 | if (err) | 1667 | if (err) |
1673 | goto out0; | 1668 | goto out2; |
1674 | 1669 | ||
1675 | #ifdef CONFIG_PROC_FS | 1670 | #ifdef CONFIG_PROC_FS |
1676 | rpc_proc_register(&init_net, &nfs_rpcstat); | 1671 | rpc_proc_register(&init_net, &nfs_rpcstat); |
1677 | #endif | 1672 | #endif |
1673 | |||
1674 | #ifdef CONFIG_NFS_V4 | ||
1675 | err = init_nfs_v4(); | ||
1676 | if (err) | ||
1677 | goto out1; | ||
1678 | #endif | ||
1679 | |||
1678 | if ((err = register_nfs_fs()) != 0) | 1680 | if ((err = register_nfs_fs()) != 0) |
1679 | goto out; | 1681 | goto out0; |
1682 | |||
1680 | return 0; | 1683 | return 0; |
1681 | out: | 1684 | out0: |
1685 | #ifdef CONFIG_NFS_V4 | ||
1686 | exit_nfs_v4(); | ||
1687 | out1: | ||
1688 | #endif | ||
1682 | #ifdef CONFIG_PROC_FS | 1689 | #ifdef CONFIG_PROC_FS |
1683 | rpc_proc_unregister(&init_net, "nfs"); | 1690 | rpc_proc_unregister(&init_net, "nfs"); |
1684 | #endif | 1691 | #endif |
1685 | nfs_destroy_directcache(); | 1692 | nfs_destroy_directcache(); |
1686 | out0: | ||
1687 | nfs_destroy_writepagecache(); | ||
1688 | out1: | ||
1689 | nfs_destroy_readpagecache(); | ||
1690 | out2: | 1693 | out2: |
1691 | nfs_destroy_inodecache(); | 1694 | nfs_destroy_writepagecache(); |
1692 | out3: | 1695 | out3: |
1693 | nfs_destroy_nfspagecache(); | 1696 | nfs_destroy_readpagecache(); |
1694 | out4: | 1697 | out4: |
1695 | nfs_fs_proc_exit(); | 1698 | nfs_destroy_inodecache(); |
1696 | out5: | 1699 | out5: |
1697 | nfsiod_stop(); | 1700 | nfs_destroy_nfspagecache(); |
1698 | out6: | 1701 | out6: |
1699 | nfs_fscache_unregister(); | 1702 | nfs_fs_proc_exit(); |
1700 | out7: | 1703 | out7: |
1701 | unregister_pernet_subsys(&nfs_net_ops); | 1704 | nfsiod_stop(); |
1702 | out8: | 1705 | out8: |
1703 | nfs_dns_resolver_destroy(); | 1706 | nfs_fscache_unregister(); |
1704 | out9: | 1707 | out9: |
1705 | nfs_idmap_quit(); | 1708 | unregister_pernet_subsys(&nfs_net_ops); |
1706 | out10: | 1709 | out10: |
1710 | nfs_dns_resolver_destroy(); | ||
1711 | out11: | ||
1707 | return err; | 1712 | return err; |
1708 | } | 1713 | } |
1709 | 1714 | ||
1710 | static void __exit exit_nfs_fs(void) | 1715 | static void __exit exit_nfs_fs(void) |
1711 | { | 1716 | { |
1717 | #ifdef CONFIG_NFS_V4 | ||
1718 | exit_nfs_v4(); | ||
1719 | #endif | ||
1712 | nfs_destroy_directcache(); | 1720 | nfs_destroy_directcache(); |
1713 | nfs_destroy_writepagecache(); | 1721 | nfs_destroy_writepagecache(); |
1714 | nfs_destroy_readpagecache(); | 1722 | nfs_destroy_readpagecache(); |
@@ -1717,7 +1725,6 @@ static void __exit exit_nfs_fs(void) | |||
1717 | nfs_fscache_unregister(); | 1725 | nfs_fscache_unregister(); |
1718 | unregister_pernet_subsys(&nfs_net_ops); | 1726 | unregister_pernet_subsys(&nfs_net_ops); |
1719 | nfs_dns_resolver_destroy(); | 1727 | nfs_dns_resolver_destroy(); |
1720 | nfs_idmap_quit(); | ||
1721 | #ifdef CONFIG_PROC_FS | 1728 | #ifdef CONFIG_PROC_FS |
1722 | rpc_proc_unregister(&init_net, "nfs"); | 1729 | rpc_proc_unregister(&init_net, "nfs"); |
1723 | #endif | 1730 | #endif |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 18f99ef71343..cfafd13b6fe9 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -85,6 +85,17 @@ struct nfs_clone_mount { | |||
85 | */ | 85 | */ |
86 | #define NFS_MAX_READDIR_PAGES 8 | 86 | #define NFS_MAX_READDIR_PAGES 8 |
87 | 87 | ||
88 | struct nfs_client_initdata { | ||
89 | unsigned long init_flags; | ||
90 | const char *hostname; | ||
91 | const struct sockaddr *addr; | ||
92 | size_t addrlen; | ||
93 | const struct nfs_rpc_ops *rpc_ops; | ||
94 | int proto; | ||
95 | u32 minorversion; | ||
96 | struct net *net; | ||
97 | }; | ||
98 | |||
88 | /* | 99 | /* |
89 | * In-kernel mount arguments | 100 | * In-kernel mount arguments |
90 | */ | 101 | */ |
@@ -142,15 +153,36 @@ struct nfs_mount_request { | |||
142 | struct net *net; | 153 | struct net *net; |
143 | }; | 154 | }; |
144 | 155 | ||
156 | struct nfs_mount_info { | ||
157 | void (*fill_super)(struct super_block *, struct nfs_mount_info *); | ||
158 | int (*set_security)(struct super_block *, struct dentry *, struct nfs_mount_info *); | ||
159 | struct nfs_parsed_mount_data *parsed; | ||
160 | struct nfs_clone_mount *cloned; | ||
161 | struct nfs_fh *mntfh; | ||
162 | }; | ||
163 | |||
145 | extern int nfs_mount(struct nfs_mount_request *info); | 164 | extern int nfs_mount(struct nfs_mount_request *info); |
146 | extern void nfs_umount(const struct nfs_mount_request *info); | 165 | extern void nfs_umount(const struct nfs_mount_request *info); |
147 | 166 | ||
148 | /* client.c */ | 167 | /* client.c */ |
149 | extern const struct rpc_program nfs_program; | 168 | extern const struct rpc_program nfs_program; |
150 | extern void nfs_clients_init(struct net *net); | 169 | extern void nfs_clients_init(struct net *net); |
170 | extern struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *); | ||
171 | int nfs_create_rpc_client(struct nfs_client *, const struct rpc_timeout *, rpc_authflavor_t); | ||
172 | struct nfs_client *nfs_get_client(const struct nfs_client_initdata *, | ||
173 | const struct rpc_timeout *, const char *, | ||
174 | rpc_authflavor_t); | ||
175 | int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *, struct nfs_fattr *); | ||
176 | void nfs_server_insert_lists(struct nfs_server *); | ||
177 | void nfs_init_timeout_values(struct rpc_timeout *, int, unsigned int, unsigned int); | ||
178 | int nfs_init_server_rpcclient(struct nfs_server *, const struct rpc_timeout *t, | ||
179 | rpc_authflavor_t); | ||
180 | struct nfs_server *nfs_alloc_server(void); | ||
181 | void nfs_server_copy_userdata(struct nfs_server *, struct nfs_server *); | ||
151 | 182 | ||
152 | extern void nfs_cleanup_cb_ident_idr(struct net *); | 183 | extern void nfs_cleanup_cb_ident_idr(struct net *); |
153 | extern void nfs_put_client(struct nfs_client *); | 184 | extern void nfs_put_client(struct nfs_client *); |
185 | extern void nfs_free_client(struct nfs_client *); | ||
154 | extern struct nfs_client *nfs4_find_client_ident(struct net *, int); | 186 | extern struct nfs_client *nfs4_find_client_ident(struct net *, int); |
155 | extern struct nfs_client * | 187 | extern struct nfs_client * |
156 | nfs4_find_client_sessionid(struct net *, const struct sockaddr *, | 188 | nfs4_find_client_sessionid(struct net *, const struct sockaddr *, |
@@ -188,6 +220,10 @@ static inline void nfs_fs_proc_exit(void) | |||
188 | } | 220 | } |
189 | #endif | 221 | #endif |
190 | 222 | ||
223 | #ifdef CONFIG_NFS_V4_1 | ||
224 | int nfs_sockaddr_match_ipaddr(const struct sockaddr *, const struct sockaddr *); | ||
225 | #endif | ||
226 | |||
191 | /* callback_xdr.c */ | 227 | /* callback_xdr.c */ |
192 | extern struct svc_version nfs4_callback_version1; | 228 | extern struct svc_version nfs4_callback_version1; |
193 | extern struct svc_version nfs4_callback_version4; | 229 | extern struct svc_version nfs4_callback_version4; |
@@ -245,6 +281,32 @@ extern struct nfs_client *nfs_init_client(struct nfs_client *clp, | |||
245 | /* dir.c */ | 281 | /* dir.c */ |
246 | extern int nfs_access_cache_shrinker(struct shrinker *shrink, | 282 | extern int nfs_access_cache_shrinker(struct shrinker *shrink, |
247 | struct shrink_control *sc); | 283 | struct shrink_control *sc); |
284 | struct dentry *nfs_lookup(struct inode *, struct dentry *, unsigned int); | ||
285 | int nfs_create(struct inode *, struct dentry *, umode_t, bool); | ||
286 | int nfs_mkdir(struct inode *, struct dentry *, umode_t); | ||
287 | int nfs_rmdir(struct inode *, struct dentry *); | ||
288 | int nfs_unlink(struct inode *, struct dentry *); | ||
289 | int nfs_symlink(struct inode *, struct dentry *, const char *); | ||
290 | int nfs_link(struct dentry *, struct inode *, struct dentry *); | ||
291 | int nfs_mknod(struct inode *, struct dentry *, umode_t, dev_t); | ||
292 | int nfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); | ||
293 | |||
294 | /* file.c */ | ||
295 | int nfs_file_fsync_commit(struct file *, loff_t, loff_t, int); | ||
296 | loff_t nfs_file_llseek(struct file *, loff_t, int); | ||
297 | int nfs_file_flush(struct file *, fl_owner_t); | ||
298 | ssize_t nfs_file_read(struct kiocb *, const struct iovec *, unsigned long, loff_t); | ||
299 | ssize_t nfs_file_splice_read(struct file *, loff_t *, struct pipe_inode_info *, | ||
300 | size_t, unsigned int); | ||
301 | int nfs_file_mmap(struct file *, struct vm_area_struct *); | ||
302 | ssize_t nfs_file_write(struct kiocb *, const struct iovec *, unsigned long, loff_t); | ||
303 | int nfs_file_release(struct inode *, struct file *); | ||
304 | int nfs_lock(struct file *, int, struct file_lock *); | ||
305 | int nfs_flock(struct file *, int, struct file_lock *); | ||
306 | ssize_t nfs_file_splice_write(struct pipe_inode_info *, struct file *, loff_t *, | ||
307 | size_t, unsigned int); | ||
308 | int nfs_check_flags(int); | ||
309 | int nfs_setlease(struct file *, long, struct file_lock **); | ||
248 | 310 | ||
249 | /* inode.c */ | 311 | /* inode.c */ |
250 | extern struct workqueue_struct *nfsiod_workqueue; | 312 | extern struct workqueue_struct *nfsiod_workqueue; |
@@ -264,6 +326,16 @@ extern struct file_system_type nfs_xdev_fs_type; | |||
264 | extern struct file_system_type nfs4_xdev_fs_type; | 326 | extern struct file_system_type nfs4_xdev_fs_type; |
265 | extern struct file_system_type nfs4_referral_fs_type; | 327 | extern struct file_system_type nfs4_referral_fs_type; |
266 | #endif | 328 | #endif |
329 | void nfs_initialise_sb(struct super_block *); | ||
330 | int nfs_set_sb_security(struct super_block *, struct dentry *, struct nfs_mount_info *); | ||
331 | int nfs_clone_sb_security(struct super_block *, struct dentry *, struct nfs_mount_info *); | ||
332 | struct dentry *nfs_fs_mount_common(struct file_system_type *, struct nfs_server *, | ||
333 | int, const char *, struct nfs_mount_info *); | ||
334 | struct dentry *nfs_fs_mount(struct file_system_type *, int, const char *, void *); | ||
335 | struct dentry * nfs_xdev_mount_common(struct file_system_type *, int, | ||
336 | const char *, struct nfs_mount_info *); | ||
337 | void nfs_kill_super(struct super_block *); | ||
338 | void nfs_fill_super(struct super_block *, struct nfs_mount_info *); | ||
267 | 339 | ||
268 | extern struct rpc_stat nfs_rpcstat; | 340 | extern struct rpc_stat nfs_rpcstat; |
269 | 341 | ||
@@ -304,12 +376,23 @@ extern int nfs_initiate_read(struct rpc_clnt *clnt, | |||
304 | extern void nfs_read_prepare(struct rpc_task *task, void *calldata); | 376 | extern void nfs_read_prepare(struct rpc_task *task, void *calldata); |
305 | extern int nfs_generic_pagein(struct nfs_pageio_descriptor *desc, | 377 | extern int nfs_generic_pagein(struct nfs_pageio_descriptor *desc, |
306 | struct nfs_pgio_header *hdr); | 378 | struct nfs_pgio_header *hdr); |
307 | extern void nfs_pageio_init_read_mds(struct nfs_pageio_descriptor *pgio, | 379 | extern void nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, |
308 | struct inode *inode, | 380 | struct inode *inode, |
309 | const struct nfs_pgio_completion_ops *compl_ops); | 381 | const struct nfs_pgio_completion_ops *compl_ops); |
310 | extern void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio); | 382 | extern void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio); |
311 | extern void nfs_readdata_release(struct nfs_read_data *rdata); | 383 | extern void nfs_readdata_release(struct nfs_read_data *rdata); |
312 | 384 | ||
385 | /* super.c */ | ||
386 | void nfs_clone_super(struct super_block *, struct nfs_mount_info *); | ||
387 | void nfs_umount_begin(struct super_block *); | ||
388 | int nfs_statfs(struct dentry *, struct kstatfs *); | ||
389 | int nfs_show_options(struct seq_file *, struct dentry *); | ||
390 | int nfs_show_devname(struct seq_file *, struct dentry *); | ||
391 | int nfs_show_path(struct seq_file *, struct dentry *); | ||
392 | int nfs_show_stats(struct seq_file *, struct dentry *); | ||
393 | void nfs_put_super(struct super_block *); | ||
394 | int nfs_remount(struct super_block *sb, int *flags, char *raw_data); | ||
395 | |||
313 | /* write.c */ | 396 | /* write.c */ |
314 | extern void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, | 397 | extern void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, |
315 | struct inode *inode, int ioflags, | 398 | struct inode *inode, int ioflags, |
@@ -318,7 +401,7 @@ extern struct nfs_write_header *nfs_writehdr_alloc(void); | |||
318 | extern void nfs_writehdr_free(struct nfs_pgio_header *hdr); | 401 | extern void nfs_writehdr_free(struct nfs_pgio_header *hdr); |
319 | extern int nfs_generic_flush(struct nfs_pageio_descriptor *desc, | 402 | extern int nfs_generic_flush(struct nfs_pageio_descriptor *desc, |
320 | struct nfs_pgio_header *hdr); | 403 | struct nfs_pgio_header *hdr); |
321 | extern void nfs_pageio_init_write_mds(struct nfs_pageio_descriptor *pgio, | 404 | extern void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, |
322 | struct inode *inode, int ioflags, | 405 | struct inode *inode, int ioflags, |
323 | const struct nfs_pgio_completion_ops *compl_ops); | 406 | const struct nfs_pgio_completion_ops *compl_ops); |
324 | extern void nfs_pageio_reset_write_mds(struct nfs_pageio_descriptor *pgio); | 407 | extern void nfs_pageio_reset_write_mds(struct nfs_pageio_descriptor *pgio); |
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index baf759bccd05..d04f0df7be55 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c | |||
@@ -106,19 +106,16 @@ static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) | |||
106 | static int decode_nfsdata(struct xdr_stream *xdr, struct nfs_readres *result) | 106 | static int decode_nfsdata(struct xdr_stream *xdr, struct nfs_readres *result) |
107 | { | 107 | { |
108 | u32 recvd, count; | 108 | u32 recvd, count; |
109 | size_t hdrlen; | ||
110 | __be32 *p; | 109 | __be32 *p; |
111 | 110 | ||
112 | p = xdr_inline_decode(xdr, 4); | 111 | p = xdr_inline_decode(xdr, 4); |
113 | if (unlikely(p == NULL)) | 112 | if (unlikely(p == NULL)) |
114 | goto out_overflow; | 113 | goto out_overflow; |
115 | count = be32_to_cpup(p); | 114 | count = be32_to_cpup(p); |
116 | hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; | 115 | recvd = xdr_read_pages(xdr, count); |
117 | recvd = xdr->buf->len - hdrlen; | ||
118 | if (unlikely(count > recvd)) | 116 | if (unlikely(count > recvd)) |
119 | goto out_cheating; | 117 | goto out_cheating; |
120 | out: | 118 | out: |
121 | xdr_read_pages(xdr, count); | ||
122 | result->eof = 0; /* NFSv2 does not pass EOF flag on the wire. */ | 119 | result->eof = 0; /* NFSv2 does not pass EOF flag on the wire. */ |
123 | result->count = count; | 120 | result->count = count; |
124 | return count; | 121 | return count; |
@@ -440,7 +437,6 @@ static void encode_path(struct xdr_stream *xdr, struct page **pages, u32 length) | |||
440 | static int decode_path(struct xdr_stream *xdr) | 437 | static int decode_path(struct xdr_stream *xdr) |
441 | { | 438 | { |
442 | u32 length, recvd; | 439 | u32 length, recvd; |
443 | size_t hdrlen; | ||
444 | __be32 *p; | 440 | __be32 *p; |
445 | 441 | ||
446 | p = xdr_inline_decode(xdr, 4); | 442 | p = xdr_inline_decode(xdr, 4); |
@@ -449,12 +445,9 @@ static int decode_path(struct xdr_stream *xdr) | |||
449 | length = be32_to_cpup(p); | 445 | length = be32_to_cpup(p); |
450 | if (unlikely(length >= xdr->buf->page_len || length > NFS_MAXPATHLEN)) | 446 | if (unlikely(length >= xdr->buf->page_len || length > NFS_MAXPATHLEN)) |
451 | goto out_size; | 447 | goto out_size; |
452 | hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; | 448 | recvd = xdr_read_pages(xdr, length); |
453 | recvd = xdr->buf->len - hdrlen; | ||
454 | if (unlikely(length > recvd)) | 449 | if (unlikely(length > recvd)) |
455 | goto out_cheating; | 450 | goto out_cheating; |
456 | |||
457 | xdr_read_pages(xdr, length); | ||
458 | xdr_terminate_string(xdr->buf, length); | 451 | xdr_terminate_string(xdr->buf, length); |
459 | return 0; | 452 | return 0; |
460 | out_size: | 453 | out_size: |
@@ -972,22 +965,7 @@ out_overflow: | |||
972 | */ | 965 | */ |
973 | static int decode_readdirok(struct xdr_stream *xdr) | 966 | static int decode_readdirok(struct xdr_stream *xdr) |
974 | { | 967 | { |
975 | u32 recvd, pglen; | 968 | return xdr_read_pages(xdr, xdr->buf->page_len); |
976 | size_t hdrlen; | ||
977 | |||
978 | pglen = xdr->buf->page_len; | ||
979 | hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; | ||
980 | recvd = xdr->buf->len - hdrlen; | ||
981 | if (unlikely(pglen > recvd)) | ||
982 | goto out_cheating; | ||
983 | out: | ||
984 | xdr_read_pages(xdr, pglen); | ||
985 | return pglen; | ||
986 | out_cheating: | ||
987 | dprintk("NFS: server cheating in readdir result: " | ||
988 | "pglen %u > recvd %u\n", pglen, recvd); | ||
989 | pglen = recvd; | ||
990 | goto out; | ||
991 | } | 969 | } |
992 | 970 | ||
993 | static int nfs2_xdr_dec_readdirres(struct rpc_rqst *req, | 971 | static int nfs2_xdr_dec_readdirres(struct rpc_rqst *req, |
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 3187e24e8f78..65d23eb92fe0 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
@@ -877,6 +877,46 @@ nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl) | |||
877 | return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl); | 877 | return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl); |
878 | } | 878 | } |
879 | 879 | ||
880 | static int nfs3_have_delegation(struct inode *inode, fmode_t flags) | ||
881 | { | ||
882 | return 0; | ||
883 | } | ||
884 | |||
885 | static int nfs3_return_delegation(struct inode *inode) | ||
886 | { | ||
887 | nfs_wb_all(inode); | ||
888 | return 0; | ||
889 | } | ||
890 | |||
891 | static const struct inode_operations nfs3_dir_inode_operations = { | ||
892 | .create = nfs_create, | ||
893 | .lookup = nfs_lookup, | ||
894 | .link = nfs_link, | ||
895 | .unlink = nfs_unlink, | ||
896 | .symlink = nfs_symlink, | ||
897 | .mkdir = nfs_mkdir, | ||
898 | .rmdir = nfs_rmdir, | ||
899 | .mknod = nfs_mknod, | ||
900 | .rename = nfs_rename, | ||
901 | .permission = nfs_permission, | ||
902 | .getattr = nfs_getattr, | ||
903 | .setattr = nfs_setattr, | ||
904 | .listxattr = nfs3_listxattr, | ||
905 | .getxattr = nfs3_getxattr, | ||
906 | .setxattr = nfs3_setxattr, | ||
907 | .removexattr = nfs3_removexattr, | ||
908 | }; | ||
909 | |||
910 | static const struct inode_operations nfs3_file_inode_operations = { | ||
911 | .permission = nfs_permission, | ||
912 | .getattr = nfs_getattr, | ||
913 | .setattr = nfs_setattr, | ||
914 | .listxattr = nfs3_listxattr, | ||
915 | .getxattr = nfs3_getxattr, | ||
916 | .setxattr = nfs3_setxattr, | ||
917 | .removexattr = nfs3_removexattr, | ||
918 | }; | ||
919 | |||
880 | const struct nfs_rpc_ops nfs_v3_clientops = { | 920 | const struct nfs_rpc_ops nfs_v3_clientops = { |
881 | .version = 3, /* protocol version */ | 921 | .version = 3, /* protocol version */ |
882 | .dentry_ops = &nfs_dentry_operations, | 922 | .dentry_ops = &nfs_dentry_operations, |
@@ -910,9 +950,11 @@ const struct nfs_rpc_ops nfs_v3_clientops = { | |||
910 | .pathconf = nfs3_proc_pathconf, | 950 | .pathconf = nfs3_proc_pathconf, |
911 | .decode_dirent = nfs3_decode_dirent, | 951 | .decode_dirent = nfs3_decode_dirent, |
912 | .read_setup = nfs3_proc_read_setup, | 952 | .read_setup = nfs3_proc_read_setup, |
953 | .read_pageio_init = nfs_pageio_init_read, | ||
913 | .read_rpc_prepare = nfs3_proc_read_rpc_prepare, | 954 | .read_rpc_prepare = nfs3_proc_read_rpc_prepare, |
914 | .read_done = nfs3_read_done, | 955 | .read_done = nfs3_read_done, |
915 | .write_setup = nfs3_proc_write_setup, | 956 | .write_setup = nfs3_proc_write_setup, |
957 | .write_pageio_init = nfs_pageio_init_write, | ||
916 | .write_rpc_prepare = nfs3_proc_write_rpc_prepare, | 958 | .write_rpc_prepare = nfs3_proc_write_rpc_prepare, |
917 | .write_done = nfs3_write_done, | 959 | .write_done = nfs3_write_done, |
918 | .commit_setup = nfs3_proc_commit_setup, | 960 | .commit_setup = nfs3_proc_commit_setup, |
@@ -921,5 +963,9 @@ const struct nfs_rpc_ops nfs_v3_clientops = { | |||
921 | .lock = nfs3_proc_lock, | 963 | .lock = nfs3_proc_lock, |
922 | .clear_acl_cache = nfs3_forget_cached_acls, | 964 | .clear_acl_cache = nfs3_forget_cached_acls, |
923 | .close_context = nfs_close_context, | 965 | .close_context = nfs_close_context, |
966 | .have_delegation = nfs3_have_delegation, | ||
967 | .return_delegation = nfs3_return_delegation, | ||
968 | .alloc_client = nfs_alloc_client, | ||
924 | .init_client = nfs_init_client, | 969 | .init_client = nfs_init_client, |
970 | .free_client = nfs_free_client, | ||
925 | }; | 971 | }; |
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index 902de489ec9b..6cbe89400dfc 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c | |||
@@ -246,7 +246,6 @@ static void encode_nfspath3(struct xdr_stream *xdr, struct page **pages, | |||
246 | static int decode_nfspath3(struct xdr_stream *xdr) | 246 | static int decode_nfspath3(struct xdr_stream *xdr) |
247 | { | 247 | { |
248 | u32 recvd, count; | 248 | u32 recvd, count; |
249 | size_t hdrlen; | ||
250 | __be32 *p; | 249 | __be32 *p; |
251 | 250 | ||
252 | p = xdr_inline_decode(xdr, 4); | 251 | p = xdr_inline_decode(xdr, 4); |
@@ -255,12 +254,9 @@ static int decode_nfspath3(struct xdr_stream *xdr) | |||
255 | count = be32_to_cpup(p); | 254 | count = be32_to_cpup(p); |
256 | if (unlikely(count >= xdr->buf->page_len || count > NFS3_MAXPATHLEN)) | 255 | if (unlikely(count >= xdr->buf->page_len || count > NFS3_MAXPATHLEN)) |
257 | goto out_nametoolong; | 256 | goto out_nametoolong; |
258 | hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; | 257 | recvd = xdr_read_pages(xdr, count); |
259 | recvd = xdr->buf->len - hdrlen; | ||
260 | if (unlikely(count > recvd)) | 258 | if (unlikely(count > recvd)) |
261 | goto out_cheating; | 259 | goto out_cheating; |
262 | |||
263 | xdr_read_pages(xdr, count); | ||
264 | xdr_terminate_string(xdr->buf, count); | 260 | xdr_terminate_string(xdr->buf, count); |
265 | return 0; | 261 | return 0; |
266 | 262 | ||
@@ -329,14 +325,14 @@ static void encode_createverf3(struct xdr_stream *xdr, const __be32 *verifier) | |||
329 | memcpy(p, verifier, NFS3_CREATEVERFSIZE); | 325 | memcpy(p, verifier, NFS3_CREATEVERFSIZE); |
330 | } | 326 | } |
331 | 327 | ||
332 | static int decode_writeverf3(struct xdr_stream *xdr, __be32 *verifier) | 328 | static int decode_writeverf3(struct xdr_stream *xdr, struct nfs_write_verifier *verifier) |
333 | { | 329 | { |
334 | __be32 *p; | 330 | __be32 *p; |
335 | 331 | ||
336 | p = xdr_inline_decode(xdr, NFS3_WRITEVERFSIZE); | 332 | p = xdr_inline_decode(xdr, NFS3_WRITEVERFSIZE); |
337 | if (unlikely(p == NULL)) | 333 | if (unlikely(p == NULL)) |
338 | goto out_overflow; | 334 | goto out_overflow; |
339 | memcpy(verifier, p, NFS3_WRITEVERFSIZE); | 335 | memcpy(verifier->data, p, NFS3_WRITEVERFSIZE); |
340 | return 0; | 336 | return 0; |
341 | out_overflow: | 337 | out_overflow: |
342 | print_overflow_msg(__func__, xdr); | 338 | print_overflow_msg(__func__, xdr); |
@@ -1587,7 +1583,6 @@ static int decode_read3resok(struct xdr_stream *xdr, | |||
1587 | struct nfs_readres *result) | 1583 | struct nfs_readres *result) |
1588 | { | 1584 | { |
1589 | u32 eof, count, ocount, recvd; | 1585 | u32 eof, count, ocount, recvd; |
1590 | size_t hdrlen; | ||
1591 | __be32 *p; | 1586 | __be32 *p; |
1592 | 1587 | ||
1593 | p = xdr_inline_decode(xdr, 4 + 4 + 4); | 1588 | p = xdr_inline_decode(xdr, 4 + 4 + 4); |
@@ -1598,13 +1593,10 @@ static int decode_read3resok(struct xdr_stream *xdr, | |||
1598 | ocount = be32_to_cpup(p++); | 1593 | ocount = be32_to_cpup(p++); |
1599 | if (unlikely(ocount != count)) | 1594 | if (unlikely(ocount != count)) |
1600 | goto out_mismatch; | 1595 | goto out_mismatch; |
1601 | hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; | 1596 | recvd = xdr_read_pages(xdr, count); |
1602 | recvd = xdr->buf->len - hdrlen; | ||
1603 | if (unlikely(count > recvd)) | 1597 | if (unlikely(count > recvd)) |
1604 | goto out_cheating; | 1598 | goto out_cheating; |
1605 | |||
1606 | out: | 1599 | out: |
1607 | xdr_read_pages(xdr, count); | ||
1608 | result->eof = eof; | 1600 | result->eof = eof; |
1609 | result->count = count; | 1601 | result->count = count; |
1610 | return count; | 1602 | return count; |
@@ -1676,20 +1668,22 @@ static int decode_write3resok(struct xdr_stream *xdr, | |||
1676 | { | 1668 | { |
1677 | __be32 *p; | 1669 | __be32 *p; |
1678 | 1670 | ||
1679 | p = xdr_inline_decode(xdr, 4 + 4 + NFS3_WRITEVERFSIZE); | 1671 | p = xdr_inline_decode(xdr, 4 + 4); |
1680 | if (unlikely(p == NULL)) | 1672 | if (unlikely(p == NULL)) |
1681 | goto out_overflow; | 1673 | goto out_overflow; |
1682 | result->count = be32_to_cpup(p++); | 1674 | result->count = be32_to_cpup(p++); |
1683 | result->verf->committed = be32_to_cpup(p++); | 1675 | result->verf->committed = be32_to_cpup(p++); |
1684 | if (unlikely(result->verf->committed > NFS_FILE_SYNC)) | 1676 | if (unlikely(result->verf->committed > NFS_FILE_SYNC)) |
1685 | goto out_badvalue; | 1677 | goto out_badvalue; |
1686 | memcpy(result->verf->verifier, p, NFS3_WRITEVERFSIZE); | 1678 | if (decode_writeverf3(xdr, &result->verf->verifier)) |
1679 | goto out_eio; | ||
1687 | return result->count; | 1680 | return result->count; |
1688 | out_badvalue: | 1681 | out_badvalue: |
1689 | dprintk("NFS: bad stable_how value: %u\n", result->verf->committed); | 1682 | dprintk("NFS: bad stable_how value: %u\n", result->verf->committed); |
1690 | return -EIO; | 1683 | return -EIO; |
1691 | out_overflow: | 1684 | out_overflow: |
1692 | print_overflow_msg(__func__, xdr); | 1685 | print_overflow_msg(__func__, xdr); |
1686 | out_eio: | ||
1693 | return -EIO; | 1687 | return -EIO; |
1694 | } | 1688 | } |
1695 | 1689 | ||
@@ -2039,22 +2033,7 @@ out_truncated: | |||
2039 | */ | 2033 | */ |
2040 | static int decode_dirlist3(struct xdr_stream *xdr) | 2034 | static int decode_dirlist3(struct xdr_stream *xdr) |
2041 | { | 2035 | { |
2042 | u32 recvd, pglen; | 2036 | return xdr_read_pages(xdr, xdr->buf->page_len); |
2043 | size_t hdrlen; | ||
2044 | |||
2045 | pglen = xdr->buf->page_len; | ||
2046 | hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; | ||
2047 | recvd = xdr->buf->len - hdrlen; | ||
2048 | if (unlikely(pglen > recvd)) | ||
2049 | goto out_cheating; | ||
2050 | out: | ||
2051 | xdr_read_pages(xdr, pglen); | ||
2052 | return pglen; | ||
2053 | out_cheating: | ||
2054 | dprintk("NFS: server cheating in readdir result: " | ||
2055 | "pglen %u > recvd %u\n", pglen, recvd); | ||
2056 | pglen = recvd; | ||
2057 | goto out; | ||
2058 | } | 2037 | } |
2059 | 2038 | ||
2060 | static int decode_readdir3resok(struct xdr_stream *xdr, | 2039 | static int decode_readdir3resok(struct xdr_stream *xdr, |
@@ -2337,7 +2316,7 @@ static int nfs3_xdr_dec_commit3res(struct rpc_rqst *req, | |||
2337 | goto out; | 2316 | goto out; |
2338 | if (status != NFS3_OK) | 2317 | if (status != NFS3_OK) |
2339 | goto out_status; | 2318 | goto out_status; |
2340 | error = decode_writeverf3(xdr, result->verf->verifier); | 2319 | error = decode_writeverf3(xdr, &result->verf->verifier); |
2341 | out: | 2320 | out: |
2342 | return error; | 2321 | return error; |
2343 | out_status: | 2322 | out_status: |
@@ -2364,7 +2343,7 @@ static inline int decode_getacl3resok(struct xdr_stream *xdr, | |||
2364 | if (result->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) | 2343 | if (result->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) |
2365 | goto out; | 2344 | goto out; |
2366 | 2345 | ||
2367 | hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; | 2346 | hdrlen = xdr_stream_pos(xdr); |
2368 | 2347 | ||
2369 | acl = NULL; | 2348 | acl = NULL; |
2370 | if (result->mask & NFS_ACL) | 2349 | if (result->mask & NFS_ACL) |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index cc5900ac61b5..5511690de8a5 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -200,7 +200,13 @@ struct nfs4_state_maintenance_ops { | |||
200 | }; | 200 | }; |
201 | 201 | ||
202 | extern const struct dentry_operations nfs4_dentry_operations; | 202 | extern const struct dentry_operations nfs4_dentry_operations; |
203 | extern const struct inode_operations nfs4_dir_inode_operations; | 203 | |
204 | /* dir.c */ | ||
205 | int nfs_atomic_open(struct inode *, struct dentry *, struct file *, | ||
206 | unsigned, umode_t, int *); | ||
207 | |||
208 | /* write.c */ | ||
209 | int nfs4_write_inode(struct inode *, struct writeback_control *); | ||
204 | 210 | ||
205 | /* nfs4namespace.c */ | 211 | /* nfs4namespace.c */ |
206 | rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *); | 212 | rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *); |
@@ -301,6 +307,10 @@ extern const u32 nfs4_pathconf_bitmap[2]; | |||
301 | extern const u32 nfs4_fsinfo_bitmap[3]; | 307 | extern const u32 nfs4_fsinfo_bitmap[3]; |
302 | extern const u32 nfs4_fs_locations_bitmap[2]; | 308 | extern const u32 nfs4_fs_locations_bitmap[2]; |
303 | 309 | ||
310 | void nfs4_free_client(struct nfs_client *); | ||
311 | |||
312 | struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *); | ||
313 | |||
304 | /* nfs4renewd.c */ | 314 | /* nfs4renewd.c */ |
305 | extern void nfs4_schedule_state_renewal(struct nfs_client *); | 315 | extern void nfs4_schedule_state_renewal(struct nfs_client *); |
306 | extern void nfs4_renewd_prepare_shutdown(struct nfs_server *); | 316 | extern void nfs4_renewd_prepare_shutdown(struct nfs_server *); |
@@ -354,6 +364,27 @@ extern void nfs4_free_lock_state(struct nfs_server *server, struct nfs4_lock_sta | |||
354 | 364 | ||
355 | extern const nfs4_stateid zero_stateid; | 365 | extern const nfs4_stateid zero_stateid; |
356 | 366 | ||
367 | /* nfs4super.c */ | ||
368 | struct nfs_mount_info; | ||
369 | struct dentry *nfs4_try_mount(int, const char *, struct nfs_mount_info *); | ||
370 | int init_nfs_v4(void); | ||
371 | void exit_nfs_v4(void); | ||
372 | |||
373 | /* nfs4sysctl.c */ | ||
374 | #ifdef CONFIG_SYSCTL | ||
375 | int nfs4_register_sysctl(void); | ||
376 | void nfs4_unregister_sysctl(void); | ||
377 | #else | ||
378 | static inline int nfs4_register_sysctl(void) | ||
379 | { | ||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | static inline void nfs4_unregister_sysctl(void) | ||
384 | { | ||
385 | } | ||
386 | #endif | ||
387 | |||
357 | /* nfs4xdr.c */ | 388 | /* nfs4xdr.c */ |
358 | extern struct rpc_procinfo nfs4_procedures[]; | 389 | extern struct rpc_procinfo nfs4_procedures[]; |
359 | 390 | ||
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c new file mode 100644 index 000000000000..1c3f13c8e472 --- /dev/null +++ b/fs/nfs/nfs4client.c | |||
@@ -0,0 +1,663 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. | ||
3 | * Written by David Howells (dhowells@redhat.com) | ||
4 | */ | ||
5 | #include <linux/module.h> | ||
6 | #include <linux/nfs_fs.h> | ||
7 | #include <linux/nfs_idmap.h> | ||
8 | #include <linux/nfs_mount.h> | ||
9 | #include <linux/sunrpc/auth.h> | ||
10 | #include <linux/sunrpc/xprt.h> | ||
11 | #include <linux/sunrpc/bc_xprt.h> | ||
12 | #include "internal.h" | ||
13 | #include "callback.h" | ||
14 | #include "delegation.h" | ||
15 | #include "pnfs.h" | ||
16 | #include "netns.h" | ||
17 | |||
18 | #define NFSDBG_FACILITY NFSDBG_CLIENT | ||
19 | |||
20 | /* | ||
21 | * Turn off NFSv4 uid/gid mapping when using AUTH_SYS | ||
22 | */ | ||
23 | static bool nfs4_disable_idmapping = true; | ||
24 | |||
25 | /* | ||
26 | * Get a unique NFSv4.0 callback identifier which will be used | ||
27 | * by the V4.0 callback service to lookup the nfs_client struct | ||
28 | */ | ||
29 | static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion) | ||
30 | { | ||
31 | int ret = 0; | ||
32 | struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id); | ||
33 | |||
34 | if (clp->rpc_ops->version != 4 || minorversion != 0) | ||
35 | return ret; | ||
36 | retry: | ||
37 | if (!idr_pre_get(&nn->cb_ident_idr, GFP_KERNEL)) | ||
38 | return -ENOMEM; | ||
39 | spin_lock(&nn->nfs_client_lock); | ||
40 | ret = idr_get_new(&nn->cb_ident_idr, clp, &clp->cl_cb_ident); | ||
41 | spin_unlock(&nn->nfs_client_lock); | ||
42 | if (ret == -EAGAIN) | ||
43 | goto retry; | ||
44 | return ret; | ||
45 | } | ||
46 | |||
47 | #ifdef CONFIG_NFS_V4_1 | ||
48 | static void nfs4_shutdown_session(struct nfs_client *clp) | ||
49 | { | ||
50 | if (nfs4_has_session(clp)) { | ||
51 | nfs4_destroy_session(clp->cl_session); | ||
52 | nfs4_destroy_clientid(clp); | ||
53 | } | ||
54 | |||
55 | } | ||
56 | #else /* CONFIG_NFS_V4_1 */ | ||
57 | static void nfs4_shutdown_session(struct nfs_client *clp) | ||
58 | { | ||
59 | } | ||
60 | #endif /* CONFIG_NFS_V4_1 */ | ||
61 | |||
62 | struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init) | ||
63 | { | ||
64 | int err; | ||
65 | struct nfs_client *clp = nfs_alloc_client(cl_init); | ||
66 | if (IS_ERR(clp)) | ||
67 | return clp; | ||
68 | |||
69 | err = nfs_get_cb_ident_idr(clp, cl_init->minorversion); | ||
70 | if (err) | ||
71 | goto error; | ||
72 | |||
73 | spin_lock_init(&clp->cl_lock); | ||
74 | INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state); | ||
75 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); | ||
76 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; | ||
77 | clp->cl_minorversion = cl_init->minorversion; | ||
78 | clp->cl_mvops = nfs_v4_minor_ops[cl_init->minorversion]; | ||
79 | return clp; | ||
80 | |||
81 | error: | ||
82 | kfree(clp); | ||
83 | return ERR_PTR(err); | ||
84 | } | ||
85 | |||
86 | /* | ||
87 | * Destroy the NFS4 callback service | ||
88 | */ | ||
89 | static void nfs4_destroy_callback(struct nfs_client *clp) | ||
90 | { | ||
91 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | ||
92 | nfs_callback_down(clp->cl_mvops->minor_version); | ||
93 | } | ||
94 | |||
95 | static void nfs4_shutdown_client(struct nfs_client *clp) | ||
96 | { | ||
97 | if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state)) | ||
98 | nfs4_kill_renewd(clp); | ||
99 | nfs4_shutdown_session(clp); | ||
100 | nfs4_destroy_callback(clp); | ||
101 | if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state)) | ||
102 | nfs_idmap_delete(clp); | ||
103 | |||
104 | rpc_destroy_wait_queue(&clp->cl_rpcwaitq); | ||
105 | kfree(clp->cl_serverowner); | ||
106 | kfree(clp->cl_serverscope); | ||
107 | kfree(clp->cl_implid); | ||
108 | } | ||
109 | |||
110 | void nfs4_free_client(struct nfs_client *clp) | ||
111 | { | ||
112 | nfs4_shutdown_client(clp); | ||
113 | nfs_free_client(clp); | ||
114 | } | ||
115 | |||
116 | /* | ||
117 | * Initialize the NFS4 callback service | ||
118 | */ | ||
119 | static int nfs4_init_callback(struct nfs_client *clp) | ||
120 | { | ||
121 | int error; | ||
122 | |||
123 | if (clp->rpc_ops->version == 4) { | ||
124 | struct rpc_xprt *xprt; | ||
125 | |||
126 | xprt = rcu_dereference_raw(clp->cl_rpcclient->cl_xprt); | ||
127 | |||
128 | if (nfs4_has_session(clp)) { | ||
129 | error = xprt_setup_backchannel(xprt, | ||
130 | NFS41_BC_MIN_CALLBACKS); | ||
131 | if (error < 0) | ||
132 | return error; | ||
133 | } | ||
134 | |||
135 | error = nfs_callback_up(clp->cl_mvops->minor_version, xprt); | ||
136 | if (error < 0) { | ||
137 | dprintk("%s: failed to start callback. Error = %d\n", | ||
138 | __func__, error); | ||
139 | return error; | ||
140 | } | ||
141 | __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state); | ||
142 | } | ||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | /* | ||
147 | * Initialize the minor version specific parts of an NFS4 client record | ||
148 | */ | ||
149 | static int nfs4_init_client_minor_version(struct nfs_client *clp) | ||
150 | { | ||
151 | #if defined(CONFIG_NFS_V4_1) | ||
152 | if (clp->cl_mvops->minor_version) { | ||
153 | struct nfs4_session *session = NULL; | ||
154 | /* | ||
155 | * Create the session and mark it expired. | ||
156 | * When a SEQUENCE operation encounters the expired session | ||
157 | * it will do session recovery to initialize it. | ||
158 | */ | ||
159 | session = nfs4_alloc_session(clp); | ||
160 | if (!session) | ||
161 | return -ENOMEM; | ||
162 | |||
163 | clp->cl_session = session; | ||
164 | /* | ||
165 | * The create session reply races with the server back | ||
166 | * channel probe. Mark the client NFS_CS_SESSION_INITING | ||
167 | * so that the client back channel can find the | ||
168 | * nfs_client struct | ||
169 | */ | ||
170 | nfs_mark_client_ready(clp, NFS_CS_SESSION_INITING); | ||
171 | } | ||
172 | #endif /* CONFIG_NFS_V4_1 */ | ||
173 | |||
174 | return nfs4_init_callback(clp); | ||
175 | } | ||
176 | |||
177 | /** | ||
178 | * nfs4_init_client - Initialise an NFS4 client record | ||
179 | * | ||
180 | * @clp: nfs_client to initialise | ||
181 | * @timeparms: timeout parameters for underlying RPC transport | ||
182 | * @ip_addr: callback IP address in presentation format | ||
183 | * @authflavor: authentication flavor for underlying RPC transport | ||
184 | * | ||
185 | * Returns pointer to an NFS client, or an ERR_PTR value. | ||
186 | */ | ||
187 | struct nfs_client *nfs4_init_client(struct nfs_client *clp, | ||
188 | const struct rpc_timeout *timeparms, | ||
189 | const char *ip_addr, | ||
190 | rpc_authflavor_t authflavour) | ||
191 | { | ||
192 | char buf[INET6_ADDRSTRLEN + 1]; | ||
193 | int error; | ||
194 | |||
195 | if (clp->cl_cons_state == NFS_CS_READY) { | ||
196 | /* the client is initialised already */ | ||
197 | dprintk("<-- nfs4_init_client() = 0 [already %p]\n", clp); | ||
198 | return clp; | ||
199 | } | ||
200 | |||
201 | /* Check NFS protocol revision and initialize RPC op vector */ | ||
202 | clp->rpc_ops = &nfs_v4_clientops; | ||
203 | |||
204 | __set_bit(NFS_CS_DISCRTRY, &clp->cl_flags); | ||
205 | error = nfs_create_rpc_client(clp, timeparms, authflavour); | ||
206 | if (error < 0) | ||
207 | goto error; | ||
208 | |||
209 | /* If no clientaddr= option was specified, find a usable cb address */ | ||
210 | if (ip_addr == NULL) { | ||
211 | struct sockaddr_storage cb_addr; | ||
212 | struct sockaddr *sap = (struct sockaddr *)&cb_addr; | ||
213 | |||
214 | error = rpc_localaddr(clp->cl_rpcclient, sap, sizeof(cb_addr)); | ||
215 | if (error < 0) | ||
216 | goto error; | ||
217 | error = rpc_ntop(sap, buf, sizeof(buf)); | ||
218 | if (error < 0) | ||
219 | goto error; | ||
220 | ip_addr = (const char *)buf; | ||
221 | } | ||
222 | strlcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr)); | ||
223 | |||
224 | error = nfs_idmap_new(clp); | ||
225 | if (error < 0) { | ||
226 | dprintk("%s: failed to create idmapper. Error = %d\n", | ||
227 | __func__, error); | ||
228 | goto error; | ||
229 | } | ||
230 | __set_bit(NFS_CS_IDMAP, &clp->cl_res_state); | ||
231 | |||
232 | error = nfs4_init_client_minor_version(clp); | ||
233 | if (error < 0) | ||
234 | goto error; | ||
235 | |||
236 | if (!nfs4_has_session(clp)) | ||
237 | nfs_mark_client_ready(clp, NFS_CS_READY); | ||
238 | return clp; | ||
239 | |||
240 | error: | ||
241 | nfs_mark_client_ready(clp, error); | ||
242 | nfs_put_client(clp); | ||
243 | dprintk("<-- nfs4_init_client() = xerror %d\n", error); | ||
244 | return ERR_PTR(error); | ||
245 | } | ||
246 | |||
247 | static void nfs4_destroy_server(struct nfs_server *server) | ||
248 | { | ||
249 | nfs_server_return_all_delegations(server); | ||
250 | unset_pnfs_layoutdriver(server); | ||
251 | nfs4_purge_state_owners(server); | ||
252 | } | ||
253 | |||
254 | /* | ||
255 | * NFSv4.0 callback thread helper | ||
256 | * | ||
257 | * Find a client by callback identifier | ||
258 | */ | ||
259 | struct nfs_client * | ||
260 | nfs4_find_client_ident(struct net *net, int cb_ident) | ||
261 | { | ||
262 | struct nfs_client *clp; | ||
263 | struct nfs_net *nn = net_generic(net, nfs_net_id); | ||
264 | |||
265 | spin_lock(&nn->nfs_client_lock); | ||
266 | clp = idr_find(&nn->cb_ident_idr, cb_ident); | ||
267 | if (clp) | ||
268 | atomic_inc(&clp->cl_count); | ||
269 | spin_unlock(&nn->nfs_client_lock); | ||
270 | return clp; | ||
271 | } | ||
272 | |||
273 | #if defined(CONFIG_NFS_V4_1) | ||
274 | /* Common match routine for v4.0 and v4.1 callback services */ | ||
275 | static bool nfs4_cb_match_client(const struct sockaddr *addr, | ||
276 | struct nfs_client *clp, u32 minorversion) | ||
277 | { | ||
278 | struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; | ||
279 | |||
280 | /* Don't match clients that failed to initialise */ | ||
281 | if (!(clp->cl_cons_state == NFS_CS_READY || | ||
282 | clp->cl_cons_state == NFS_CS_SESSION_INITING)) | ||
283 | return false; | ||
284 | |||
285 | smp_rmb(); | ||
286 | |||
287 | /* Match the version and minorversion */ | ||
288 | if (clp->rpc_ops->version != 4 || | ||
289 | clp->cl_minorversion != minorversion) | ||
290 | return false; | ||
291 | |||
292 | /* Match only the IP address, not the port number */ | ||
293 | if (!nfs_sockaddr_match_ipaddr(addr, clap)) | ||
294 | return false; | ||
295 | |||
296 | return true; | ||
297 | } | ||
298 | |||
299 | /* | ||
300 | * NFSv4.1 callback thread helper | ||
301 | * For CB_COMPOUND calls, find a client by IP address, protocol version, | ||
302 | * minorversion, and sessionID | ||
303 | * | ||
304 | * Returns NULL if no such client | ||
305 | */ | ||
306 | struct nfs_client * | ||
307 | nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr, | ||
308 | struct nfs4_sessionid *sid) | ||
309 | { | ||
310 | struct nfs_client *clp; | ||
311 | struct nfs_net *nn = net_generic(net, nfs_net_id); | ||
312 | |||
313 | spin_lock(&nn->nfs_client_lock); | ||
314 | list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) { | ||
315 | if (nfs4_cb_match_client(addr, clp, 1) == false) | ||
316 | continue; | ||
317 | |||
318 | if (!nfs4_has_session(clp)) | ||
319 | continue; | ||
320 | |||
321 | /* Match sessionid*/ | ||
322 | if (memcmp(clp->cl_session->sess_id.data, | ||
323 | sid->data, NFS4_MAX_SESSIONID_LEN) != 0) | ||
324 | continue; | ||
325 | |||
326 | atomic_inc(&clp->cl_count); | ||
327 | spin_unlock(&nn->nfs_client_lock); | ||
328 | return clp; | ||
329 | } | ||
330 | spin_unlock(&nn->nfs_client_lock); | ||
331 | return NULL; | ||
332 | } | ||
333 | |||
334 | #else /* CONFIG_NFS_V4_1 */ | ||
335 | |||
336 | struct nfs_client * | ||
337 | nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr, | ||
338 | struct nfs4_sessionid *sid) | ||
339 | { | ||
340 | return NULL; | ||
341 | } | ||
342 | #endif /* CONFIG_NFS_V4_1 */ | ||
343 | |||
344 | /* | ||
345 | * Set up an NFS4 client | ||
346 | */ | ||
347 | static int nfs4_set_client(struct nfs_server *server, | ||
348 | const char *hostname, | ||
349 | const struct sockaddr *addr, | ||
350 | const size_t addrlen, | ||
351 | const char *ip_addr, | ||
352 | rpc_authflavor_t authflavour, | ||
353 | int proto, const struct rpc_timeout *timeparms, | ||
354 | u32 minorversion, struct net *net) | ||
355 | { | ||
356 | struct nfs_client_initdata cl_init = { | ||
357 | .hostname = hostname, | ||
358 | .addr = addr, | ||
359 | .addrlen = addrlen, | ||
360 | .rpc_ops = &nfs_v4_clientops, | ||
361 | .proto = proto, | ||
362 | .minorversion = minorversion, | ||
363 | .net = net, | ||
364 | }; | ||
365 | struct nfs_client *clp; | ||
366 | int error; | ||
367 | |||
368 | dprintk("--> nfs4_set_client()\n"); | ||
369 | |||
370 | if (server->flags & NFS_MOUNT_NORESVPORT) | ||
371 | set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags); | ||
372 | |||
373 | /* Allocate or find a client reference we can use */ | ||
374 | clp = nfs_get_client(&cl_init, timeparms, ip_addr, authflavour); | ||
375 | if (IS_ERR(clp)) { | ||
376 | error = PTR_ERR(clp); | ||
377 | goto error; | ||
378 | } | ||
379 | |||
380 | /* | ||
381 | * Query for the lease time on clientid setup or renewal | ||
382 | * | ||
383 | * Note that this will be set on nfs_clients that were created | ||
384 | * only for the DS role and did not set this bit, but now will | ||
385 | * serve a dual role. | ||
386 | */ | ||
387 | set_bit(NFS_CS_CHECK_LEASE_TIME, &clp->cl_res_state); | ||
388 | |||
389 | server->nfs_client = clp; | ||
390 | dprintk("<-- nfs4_set_client() = 0 [new %p]\n", clp); | ||
391 | return 0; | ||
392 | error: | ||
393 | dprintk("<-- nfs4_set_client() = xerror %d\n", error); | ||
394 | return error; | ||
395 | } | ||
396 | |||
397 | /* | ||
398 | * Set up a pNFS Data Server client. | ||
399 | * | ||
400 | * Return any existing nfs_client that matches server address,port,version | ||
401 | * and minorversion. | ||
402 | * | ||
403 | * For a new nfs_client, use a soft mount (default), a low retrans and a | ||
404 | * low timeout interval so that if a connection is lost, we retry through | ||
405 | * the MDS. | ||
406 | */ | ||
407 | struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp, | ||
408 | const struct sockaddr *ds_addr, int ds_addrlen, | ||
409 | int ds_proto, unsigned int ds_timeo, unsigned int ds_retrans) | ||
410 | { | ||
411 | struct nfs_client_initdata cl_init = { | ||
412 | .addr = ds_addr, | ||
413 | .addrlen = ds_addrlen, | ||
414 | .rpc_ops = &nfs_v4_clientops, | ||
415 | .proto = ds_proto, | ||
416 | .minorversion = mds_clp->cl_minorversion, | ||
417 | .net = mds_clp->cl_net, | ||
418 | }; | ||
419 | struct rpc_timeout ds_timeout; | ||
420 | struct nfs_client *clp; | ||
421 | |||
422 | /* | ||
423 | * Set an authflavor equual to the MDS value. Use the MDS nfs_client | ||
424 | * cl_ipaddr so as to use the same EXCHANGE_ID co_ownerid as the MDS | ||
425 | * (section 13.1 RFC 5661). | ||
426 | */ | ||
427 | nfs_init_timeout_values(&ds_timeout, ds_proto, ds_timeo, ds_retrans); | ||
428 | clp = nfs_get_client(&cl_init, &ds_timeout, mds_clp->cl_ipaddr, | ||
429 | mds_clp->cl_rpcclient->cl_auth->au_flavor); | ||
430 | |||
431 | dprintk("<-- %s %p\n", __func__, clp); | ||
432 | return clp; | ||
433 | } | ||
434 | EXPORT_SYMBOL_GPL(nfs4_set_ds_client); | ||
435 | |||
436 | /* | ||
437 | * Session has been established, and the client marked ready. | ||
438 | * Set the mount rsize and wsize with negotiated fore channel | ||
439 | * attributes which will be bound checked in nfs_server_set_fsinfo. | ||
440 | */ | ||
441 | static void nfs4_session_set_rwsize(struct nfs_server *server) | ||
442 | { | ||
443 | #ifdef CONFIG_NFS_V4_1 | ||
444 | struct nfs4_session *sess; | ||
445 | u32 server_resp_sz; | ||
446 | u32 server_rqst_sz; | ||
447 | |||
448 | if (!nfs4_has_session(server->nfs_client)) | ||
449 | return; | ||
450 | sess = server->nfs_client->cl_session; | ||
451 | server_resp_sz = sess->fc_attrs.max_resp_sz - nfs41_maxread_overhead; | ||
452 | server_rqst_sz = sess->fc_attrs.max_rqst_sz - nfs41_maxwrite_overhead; | ||
453 | |||
454 | if (server->rsize > server_resp_sz) | ||
455 | server->rsize = server_resp_sz; | ||
456 | if (server->wsize > server_rqst_sz) | ||
457 | server->wsize = server_rqst_sz; | ||
458 | #endif /* CONFIG_NFS_V4_1 */ | ||
459 | } | ||
460 | |||
461 | static int nfs4_server_common_setup(struct nfs_server *server, | ||
462 | struct nfs_fh *mntfh) | ||
463 | { | ||
464 | struct nfs_fattr *fattr; | ||
465 | int error; | ||
466 | |||
467 | BUG_ON(!server->nfs_client); | ||
468 | BUG_ON(!server->nfs_client->rpc_ops); | ||
469 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | ||
470 | |||
471 | /* data servers support only a subset of NFSv4.1 */ | ||
472 | if (is_ds_only_client(server->nfs_client)) | ||
473 | return -EPROTONOSUPPORT; | ||
474 | |||
475 | fattr = nfs_alloc_fattr(); | ||
476 | if (fattr == NULL) | ||
477 | return -ENOMEM; | ||
478 | |||
479 | /* We must ensure the session is initialised first */ | ||
480 | error = nfs4_init_session(server); | ||
481 | if (error < 0) | ||
482 | goto out; | ||
483 | |||
484 | /* Probe the root fh to retrieve its FSID and filehandle */ | ||
485 | error = nfs4_get_rootfh(server, mntfh); | ||
486 | if (error < 0) | ||
487 | goto out; | ||
488 | |||
489 | dprintk("Server FSID: %llx:%llx\n", | ||
490 | (unsigned long long) server->fsid.major, | ||
491 | (unsigned long long) server->fsid.minor); | ||
492 | dprintk("Mount FH: %d\n", mntfh->size); | ||
493 | |||
494 | nfs4_session_set_rwsize(server); | ||
495 | |||
496 | error = nfs_probe_fsinfo(server, mntfh, fattr); | ||
497 | if (error < 0) | ||
498 | goto out; | ||
499 | |||
500 | if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN) | ||
501 | server->namelen = NFS4_MAXNAMLEN; | ||
502 | |||
503 | nfs_server_insert_lists(server); | ||
504 | server->mount_time = jiffies; | ||
505 | server->destroy = nfs4_destroy_server; | ||
506 | out: | ||
507 | nfs_free_fattr(fattr); | ||
508 | return error; | ||
509 | } | ||
510 | |||
511 | /* | ||
512 | * Create a version 4 volume record | ||
513 | */ | ||
514 | static int nfs4_init_server(struct nfs_server *server, | ||
515 | const struct nfs_parsed_mount_data *data) | ||
516 | { | ||
517 | struct rpc_timeout timeparms; | ||
518 | int error; | ||
519 | |||
520 | dprintk("--> nfs4_init_server()\n"); | ||
521 | |||
522 | nfs_init_timeout_values(&timeparms, data->nfs_server.protocol, | ||
523 | data->timeo, data->retrans); | ||
524 | |||
525 | /* Initialise the client representation from the mount data */ | ||
526 | server->flags = data->flags; | ||
527 | server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR|NFS_CAP_POSIX_LOCK; | ||
528 | if (!(data->flags & NFS_MOUNT_NORDIRPLUS)) | ||
529 | server->caps |= NFS_CAP_READDIRPLUS; | ||
530 | server->options = data->options; | ||
531 | |||
532 | /* Get a client record */ | ||
533 | error = nfs4_set_client(server, | ||
534 | data->nfs_server.hostname, | ||
535 | (const struct sockaddr *)&data->nfs_server.address, | ||
536 | data->nfs_server.addrlen, | ||
537 | data->client_address, | ||
538 | data->auth_flavors[0], | ||
539 | data->nfs_server.protocol, | ||
540 | &timeparms, | ||
541 | data->minorversion, | ||
542 | data->net); | ||
543 | if (error < 0) | ||
544 | goto error; | ||
545 | |||
546 | /* | ||
547 | * Don't use NFS uid/gid mapping if we're using AUTH_SYS or lower | ||
548 | * authentication. | ||
549 | */ | ||
550 | if (nfs4_disable_idmapping && data->auth_flavors[0] == RPC_AUTH_UNIX) | ||
551 | server->caps |= NFS_CAP_UIDGID_NOMAP; | ||
552 | |||
553 | if (data->rsize) | ||
554 | server->rsize = nfs_block_size(data->rsize, NULL); | ||
555 | if (data->wsize) | ||
556 | server->wsize = nfs_block_size(data->wsize, NULL); | ||
557 | |||
558 | server->acregmin = data->acregmin * HZ; | ||
559 | server->acregmax = data->acregmax * HZ; | ||
560 | server->acdirmin = data->acdirmin * HZ; | ||
561 | server->acdirmax = data->acdirmax * HZ; | ||
562 | |||
563 | server->port = data->nfs_server.port; | ||
564 | |||
565 | error = nfs_init_server_rpcclient(server, &timeparms, data->auth_flavors[0]); | ||
566 | |||
567 | error: | ||
568 | /* Done */ | ||
569 | dprintk("<-- nfs4_init_server() = %d\n", error); | ||
570 | return error; | ||
571 | } | ||
572 | |||
573 | /* | ||
574 | * Create a version 4 volume record | ||
575 | * - keyed on server and FSID | ||
576 | */ | ||
577 | struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, | ||
578 | struct nfs_fh *mntfh) | ||
579 | { | ||
580 | struct nfs_server *server; | ||
581 | int error; | ||
582 | |||
583 | dprintk("--> nfs4_create_server()\n"); | ||
584 | |||
585 | server = nfs_alloc_server(); | ||
586 | if (!server) | ||
587 | return ERR_PTR(-ENOMEM); | ||
588 | |||
589 | /* set up the general RPC client */ | ||
590 | error = nfs4_init_server(server, data); | ||
591 | if (error < 0) | ||
592 | goto error; | ||
593 | |||
594 | error = nfs4_server_common_setup(server, mntfh); | ||
595 | if (error < 0) | ||
596 | goto error; | ||
597 | |||
598 | dprintk("<-- nfs4_create_server() = %p\n", server); | ||
599 | return server; | ||
600 | |||
601 | error: | ||
602 | nfs_free_server(server); | ||
603 | dprintk("<-- nfs4_create_server() = error %d\n", error); | ||
604 | return ERR_PTR(error); | ||
605 | } | ||
606 | |||
607 | /* | ||
608 | * Create an NFS4 referral server record | ||
609 | */ | ||
610 | struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | ||
611 | struct nfs_fh *mntfh) | ||
612 | { | ||
613 | struct nfs_client *parent_client; | ||
614 | struct nfs_server *server, *parent_server; | ||
615 | int error; | ||
616 | |||
617 | dprintk("--> nfs4_create_referral_server()\n"); | ||
618 | |||
619 | server = nfs_alloc_server(); | ||
620 | if (!server) | ||
621 | return ERR_PTR(-ENOMEM); | ||
622 | |||
623 | parent_server = NFS_SB(data->sb); | ||
624 | parent_client = parent_server->nfs_client; | ||
625 | |||
626 | /* Initialise the client representation from the parent server */ | ||
627 | nfs_server_copy_userdata(server, parent_server); | ||
628 | server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR; | ||
629 | |||
630 | /* Get a client representation. | ||
631 | * Note: NFSv4 always uses TCP, */ | ||
632 | error = nfs4_set_client(server, data->hostname, | ||
633 | data->addr, | ||
634 | data->addrlen, | ||
635 | parent_client->cl_ipaddr, | ||
636 | data->authflavor, | ||
637 | rpc_protocol(parent_server->client), | ||
638 | parent_server->client->cl_timeout, | ||
639 | parent_client->cl_mvops->minor_version, | ||
640 | parent_client->cl_net); | ||
641 | if (error < 0) | ||
642 | goto error; | ||
643 | |||
644 | error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout, data->authflavor); | ||
645 | if (error < 0) | ||
646 | goto error; | ||
647 | |||
648 | error = nfs4_server_common_setup(server, mntfh); | ||
649 | if (error < 0) | ||
650 | goto error; | ||
651 | |||
652 | dprintk("<-- nfs_create_referral_server() = %p\n", server); | ||
653 | return server; | ||
654 | |||
655 | error: | ||
656 | nfs_free_server(server); | ||
657 | dprintk("<-- nfs4_create_referral_server() = error %d\n", error); | ||
658 | return ERR_PTR(error); | ||
659 | } | ||
660 | |||
661 | module_param(nfs4_disable_idmapping, bool, 0644); | ||
662 | MODULE_PARM_DESC(nfs4_disable_idmapping, | ||
663 | "Turn off NFSv4 idmapping when using 'sec=sys'"); | ||
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c new file mode 100644 index 000000000000..acb65e7887f8 --- /dev/null +++ b/fs/nfs/nfs4file.c | |||
@@ -0,0 +1,126 @@ | |||
1 | /* | ||
2 | * linux/fs/nfs/file.c | ||
3 | * | ||
4 | * Copyright (C) 1992 Rick Sladkey | ||
5 | */ | ||
6 | #include <linux/nfs_fs.h> | ||
7 | #include "internal.h" | ||
8 | #include "pnfs.h" | ||
9 | |||
10 | #define NFSDBG_FACILITY NFSDBG_FILE | ||
11 | |||
12 | static int | ||
13 | nfs4_file_open(struct inode *inode, struct file *filp) | ||
14 | { | ||
15 | struct nfs_open_context *ctx; | ||
16 | struct dentry *dentry = filp->f_path.dentry; | ||
17 | struct dentry *parent = NULL; | ||
18 | struct inode *dir; | ||
19 | unsigned openflags = filp->f_flags; | ||
20 | struct iattr attr; | ||
21 | int err; | ||
22 | |||
23 | BUG_ON(inode != dentry->d_inode); | ||
24 | /* | ||
25 | * If no cached dentry exists or if it's negative, NFSv4 handled the | ||
26 | * opens in ->lookup() or ->create(). | ||
27 | * | ||
28 | * We only get this far for a cached positive dentry. We skipped | ||
29 | * revalidation, so handle it here by dropping the dentry and returning | ||
30 | * -EOPENSTALE. The VFS will retry the lookup/create/open. | ||
31 | */ | ||
32 | |||
33 | dprintk("NFS: open file(%s/%s)\n", | ||
34 | dentry->d_parent->d_name.name, | ||
35 | dentry->d_name.name); | ||
36 | |||
37 | if ((openflags & O_ACCMODE) == 3) | ||
38 | openflags--; | ||
39 | |||
40 | /* We can't create new files here */ | ||
41 | openflags &= ~(O_CREAT|O_EXCL); | ||
42 | |||
43 | parent = dget_parent(dentry); | ||
44 | dir = parent->d_inode; | ||
45 | |||
46 | ctx = alloc_nfs_open_context(filp->f_path.dentry, filp->f_mode); | ||
47 | err = PTR_ERR(ctx); | ||
48 | if (IS_ERR(ctx)) | ||
49 | goto out; | ||
50 | |||
51 | attr.ia_valid = ATTR_OPEN; | ||
52 | if (openflags & O_TRUNC) { | ||
53 | attr.ia_valid |= ATTR_SIZE; | ||
54 | attr.ia_size = 0; | ||
55 | nfs_wb_all(inode); | ||
56 | } | ||
57 | |||
58 | inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr); | ||
59 | if (IS_ERR(inode)) { | ||
60 | err = PTR_ERR(inode); | ||
61 | switch (err) { | ||
62 | case -EPERM: | ||
63 | case -EACCES: | ||
64 | case -EDQUOT: | ||
65 | case -ENOSPC: | ||
66 | case -EROFS: | ||
67 | goto out_put_ctx; | ||
68 | default: | ||
69 | goto out_drop; | ||
70 | } | ||
71 | } | ||
72 | iput(inode); | ||
73 | if (inode != dentry->d_inode) | ||
74 | goto out_drop; | ||
75 | |||
76 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | ||
77 | nfs_file_set_open_context(filp, ctx); | ||
78 | err = 0; | ||
79 | |||
80 | out_put_ctx: | ||
81 | put_nfs_open_context(ctx); | ||
82 | out: | ||
83 | dput(parent); | ||
84 | return err; | ||
85 | |||
86 | out_drop: | ||
87 | d_drop(dentry); | ||
88 | err = -EOPENSTALE; | ||
89 | goto out_put_ctx; | ||
90 | } | ||
91 | |||
92 | static int | ||
93 | nfs4_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) | ||
94 | { | ||
95 | int ret; | ||
96 | struct inode *inode = file->f_path.dentry->d_inode; | ||
97 | |||
98 | ret = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
99 | mutex_lock(&inode->i_mutex); | ||
100 | ret = nfs_file_fsync_commit(file, start, end, datasync); | ||
101 | if (!ret && !datasync) | ||
102 | /* application has asked for meta-data sync */ | ||
103 | ret = pnfs_layoutcommit_inode(inode, true); | ||
104 | mutex_unlock(&inode->i_mutex); | ||
105 | |||
106 | return ret; | ||
107 | } | ||
108 | |||
109 | const struct file_operations nfs4_file_operations = { | ||
110 | .llseek = nfs_file_llseek, | ||
111 | .read = do_sync_read, | ||
112 | .write = do_sync_write, | ||
113 | .aio_read = nfs_file_read, | ||
114 | .aio_write = nfs_file_write, | ||
115 | .mmap = nfs_file_mmap, | ||
116 | .open = nfs4_file_open, | ||
117 | .flush = nfs_file_flush, | ||
118 | .release = nfs_file_release, | ||
119 | .fsync = nfs4_file_fsync, | ||
120 | .lock = nfs_lock, | ||
121 | .flock = nfs_flock, | ||
122 | .splice_read = nfs_file_splice_read, | ||
123 | .splice_write = nfs_file_splice_write, | ||
124 | .check_flags = nfs_check_flags, | ||
125 | .setlease = nfs_setlease, | ||
126 | }; | ||
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index e1340293872c..53f94d915bd1 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c | |||
@@ -205,9 +205,9 @@ static int filelayout_async_handle_error(struct rpc_task *task, | |||
205 | case -EPIPE: | 205 | case -EPIPE: |
206 | dprintk("%s DS connection error %d\n", __func__, | 206 | dprintk("%s DS connection error %d\n", __func__, |
207 | task->tk_status); | 207 | task->tk_status); |
208 | if (!filelayout_test_devid_invalid(devid)) | ||
209 | _pnfs_return_layout(inode); | ||
210 | filelayout_mark_devid_invalid(devid); | 208 | filelayout_mark_devid_invalid(devid); |
209 | clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(inode)->flags); | ||
210 | _pnfs_return_layout(inode); | ||
211 | rpc_wake_up(&tbl->slot_tbl_waitq); | 211 | rpc_wake_up(&tbl->slot_tbl_waitq); |
212 | nfs4_ds_disconnect(clp); | 212 | nfs4_ds_disconnect(clp); |
213 | /* fall through */ | 213 | /* fall through */ |
@@ -351,9 +351,9 @@ static void prepare_to_resend_writes(struct nfs_commit_data *data) | |||
351 | struct nfs_page *first = nfs_list_entry(data->pages.next); | 351 | struct nfs_page *first = nfs_list_entry(data->pages.next); |
352 | 352 | ||
353 | data->task.tk_status = 0; | 353 | data->task.tk_status = 0; |
354 | memcpy(data->verf.verifier, first->wb_verf.verifier, | 354 | memcpy(&data->verf.verifier, &first->wb_verf, |
355 | sizeof(first->wb_verf.verifier)); | 355 | sizeof(data->verf.verifier)); |
356 | data->verf.verifier[0]++; /* ensure verifier mismatch */ | 356 | data->verf.verifier.data[0]++; /* ensure verifier mismatch */ |
357 | } | 357 | } |
358 | 358 | ||
359 | static int filelayout_commit_done_cb(struct rpc_task *task, | 359 | static int filelayout_commit_done_cb(struct rpc_task *task, |
diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c index a1fab8da7f03..f81231f30d94 100644 --- a/fs/nfs/nfs4filelayoutdev.c +++ b/fs/nfs/nfs4filelayoutdev.c | |||
@@ -728,7 +728,7 @@ get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, gfp_t gfp_fla | |||
728 | pdev->layout_type = LAYOUT_NFSV4_1_FILES; | 728 | pdev->layout_type = LAYOUT_NFSV4_1_FILES; |
729 | pdev->pages = pages; | 729 | pdev->pages = pages; |
730 | pdev->pgbase = 0; | 730 | pdev->pgbase = 0; |
731 | pdev->pglen = PAGE_SIZE * max_pages; | 731 | pdev->pglen = max_resp_sz; |
732 | pdev->mincount = 0; | 732 | pdev->mincount = 0; |
733 | 733 | ||
734 | rc = nfs4_proc_getdeviceinfo(server, pdev); | 734 | rc = nfs4_proc_getdeviceinfo(server, pdev); |
diff --git a/fs/nfs/nfs4getroot.c b/fs/nfs/nfs4getroot.c new file mode 100644 index 000000000000..6a83780e0ce6 --- /dev/null +++ b/fs/nfs/nfs4getroot.c | |||
@@ -0,0 +1,49 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. | ||
3 | * Written by David Howells (dhowells@redhat.com) | ||
4 | */ | ||
5 | |||
6 | #include <linux/nfs_fs.h> | ||
7 | #include "nfs4_fs.h" | ||
8 | |||
9 | #define NFSDBG_FACILITY NFSDBG_CLIENT | ||
10 | |||
11 | int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh) | ||
12 | { | ||
13 | struct nfs_fsinfo fsinfo; | ||
14 | int ret = -ENOMEM; | ||
15 | |||
16 | dprintk("--> nfs4_get_rootfh()\n"); | ||
17 | |||
18 | fsinfo.fattr = nfs_alloc_fattr(); | ||
19 | if (fsinfo.fattr == NULL) | ||
20 | goto out; | ||
21 | |||
22 | /* Start by getting the root filehandle from the server */ | ||
23 | ret = nfs4_proc_get_rootfh(server, mntfh, &fsinfo); | ||
24 | if (ret < 0) { | ||
25 | dprintk("nfs4_get_rootfh: getroot error = %d\n", -ret); | ||
26 | goto out; | ||
27 | } | ||
28 | |||
29 | if (!(fsinfo.fattr->valid & NFS_ATTR_FATTR_TYPE) | ||
30 | || !S_ISDIR(fsinfo.fattr->mode)) { | ||
31 | printk(KERN_ERR "nfs4_get_rootfh:" | ||
32 | " getroot encountered non-directory\n"); | ||
33 | ret = -ENOTDIR; | ||
34 | goto out; | ||
35 | } | ||
36 | |||
37 | if (fsinfo.fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) { | ||
38 | printk(KERN_ERR "nfs4_get_rootfh:" | ||
39 | " getroot obtained referral\n"); | ||
40 | ret = -EREMOTE; | ||
41 | goto out; | ||
42 | } | ||
43 | |||
44 | memcpy(&server->fsid, &fsinfo.fattr->fsid, sizeof(server->fsid)); | ||
45 | out: | ||
46 | nfs_free_fattr(fsinfo.fattr); | ||
47 | dprintk("<-- nfs4_get_rootfh() = %d\n", ret); | ||
48 | return ret; | ||
49 | } | ||
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index c157b2089b47..6843e0a37de8 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -43,7 +43,6 @@ | |||
43 | #include <linux/printk.h> | 43 | #include <linux/printk.h> |
44 | #include <linux/slab.h> | 44 | #include <linux/slab.h> |
45 | #include <linux/sunrpc/clnt.h> | 45 | #include <linux/sunrpc/clnt.h> |
46 | #include <linux/sunrpc/gss_api.h> | ||
47 | #include <linux/nfs.h> | 46 | #include <linux/nfs.h> |
48 | #include <linux/nfs4.h> | 47 | #include <linux/nfs4.h> |
49 | #include <linux/nfs_fs.h> | 48 | #include <linux/nfs_fs.h> |
@@ -259,7 +258,12 @@ static int nfs4_wait_clnt_recover(struct nfs_client *clp) | |||
259 | 258 | ||
260 | res = wait_on_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING, | 259 | res = wait_on_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING, |
261 | nfs_wait_bit_killable, TASK_KILLABLE); | 260 | nfs_wait_bit_killable, TASK_KILLABLE); |
262 | return res; | 261 | if (res) |
262 | return res; | ||
263 | |||
264 | if (clp->cl_cons_state < 0) | ||
265 | return clp->cl_cons_state; | ||
266 | return 0; | ||
263 | } | 267 | } |
264 | 268 | ||
265 | static int nfs4_delay(struct rpc_clnt *clnt, long *timeout) | 269 | static int nfs4_delay(struct rpc_clnt *clnt, long *timeout) |
@@ -294,8 +298,8 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc | |||
294 | case 0: | 298 | case 0: |
295 | return 0; | 299 | return 0; |
296 | case -NFS4ERR_OPENMODE: | 300 | case -NFS4ERR_OPENMODE: |
297 | if (inode && nfs_have_delegation(inode, FMODE_READ)) { | 301 | if (inode && nfs4_have_delegation(inode, FMODE_READ)) { |
298 | nfs_inode_return_delegation(inode); | 302 | nfs4_inode_return_delegation(inode); |
299 | exception->retry = 1; | 303 | exception->retry = 1; |
300 | return 0; | 304 | return 0; |
301 | } | 305 | } |
@@ -1065,7 +1069,7 @@ static void nfs4_return_incompatible_delegation(struct inode *inode, fmode_t fmo | |||
1065 | return; | 1069 | return; |
1066 | } | 1070 | } |
1067 | rcu_read_unlock(); | 1071 | rcu_read_unlock(); |
1068 | nfs_inode_return_delegation(inode); | 1072 | nfs4_inode_return_delegation(inode); |
1069 | } | 1073 | } |
1070 | 1074 | ||
1071 | static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) | 1075 | static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) |
@@ -1756,33 +1760,70 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta | |||
1756 | } | 1760 | } |
1757 | 1761 | ||
1758 | #if defined(CONFIG_NFS_V4_1) | 1762 | #if defined(CONFIG_NFS_V4_1) |
1759 | static int nfs41_check_expired_stateid(struct nfs4_state *state, nfs4_stateid *stateid, unsigned int flags) | 1763 | static void nfs41_clear_delegation_stateid(struct nfs4_state *state) |
1760 | { | 1764 | { |
1761 | int status = NFS_OK; | ||
1762 | struct nfs_server *server = NFS_SERVER(state->inode); | 1765 | struct nfs_server *server = NFS_SERVER(state->inode); |
1766 | nfs4_stateid *stateid = &state->stateid; | ||
1767 | int status; | ||
1768 | |||
1769 | /* If a state reset has been done, test_stateid is unneeded */ | ||
1770 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) | ||
1771 | return; | ||
1763 | 1772 | ||
1764 | if (state->flags & flags) { | 1773 | status = nfs41_test_stateid(server, stateid); |
1765 | status = nfs41_test_stateid(server, stateid); | 1774 | if (status != NFS_OK) { |
1766 | if (status != NFS_OK) { | 1775 | /* Free the stateid unless the server explicitly |
1776 | * informs us the stateid is unrecognized. */ | ||
1777 | if (status != -NFS4ERR_BAD_STATEID) | ||
1767 | nfs41_free_stateid(server, stateid); | 1778 | nfs41_free_stateid(server, stateid); |
1768 | state->flags &= ~flags; | 1779 | |
1769 | } | 1780 | clear_bit(NFS_DELEGATED_STATE, &state->flags); |
1781 | } | ||
1782 | } | ||
1783 | |||
1784 | /** | ||
1785 | * nfs41_check_open_stateid - possibly free an open stateid | ||
1786 | * | ||
1787 | * @state: NFSv4 state for an inode | ||
1788 | * | ||
1789 | * Returns NFS_OK if recovery for this stateid is now finished. | ||
1790 | * Otherwise a negative NFS4ERR value is returned. | ||
1791 | */ | ||
1792 | static int nfs41_check_open_stateid(struct nfs4_state *state) | ||
1793 | { | ||
1794 | struct nfs_server *server = NFS_SERVER(state->inode); | ||
1795 | nfs4_stateid *stateid = &state->stateid; | ||
1796 | int status; | ||
1797 | |||
1798 | /* If a state reset has been done, test_stateid is unneeded */ | ||
1799 | if ((test_bit(NFS_O_RDONLY_STATE, &state->flags) == 0) && | ||
1800 | (test_bit(NFS_O_WRONLY_STATE, &state->flags) == 0) && | ||
1801 | (test_bit(NFS_O_RDWR_STATE, &state->flags) == 0)) | ||
1802 | return -NFS4ERR_BAD_STATEID; | ||
1803 | |||
1804 | status = nfs41_test_stateid(server, stateid); | ||
1805 | if (status != NFS_OK) { | ||
1806 | /* Free the stateid unless the server explicitly | ||
1807 | * informs us the stateid is unrecognized. */ | ||
1808 | if (status != -NFS4ERR_BAD_STATEID) | ||
1809 | nfs41_free_stateid(server, stateid); | ||
1810 | |||
1811 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); | ||
1812 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
1813 | clear_bit(NFS_O_RDWR_STATE, &state->flags); | ||
1770 | } | 1814 | } |
1771 | return status; | 1815 | return status; |
1772 | } | 1816 | } |
1773 | 1817 | ||
1774 | static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state) | 1818 | static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state) |
1775 | { | 1819 | { |
1776 | int deleg_status, open_status; | 1820 | int status; |
1777 | int deleg_flags = 1 << NFS_DELEGATED_STATE; | ||
1778 | int open_flags = (1 << NFS_O_RDONLY_STATE) | (1 << NFS_O_WRONLY_STATE) | (1 << NFS_O_RDWR_STATE); | ||
1779 | |||
1780 | deleg_status = nfs41_check_expired_stateid(state, &state->stateid, deleg_flags); | ||
1781 | open_status = nfs41_check_expired_stateid(state, &state->open_stateid, open_flags); | ||
1782 | 1821 | ||
1783 | if ((deleg_status == NFS_OK) && (open_status == NFS_OK)) | 1822 | nfs41_clear_delegation_stateid(state); |
1784 | return NFS_OK; | 1823 | status = nfs41_check_open_stateid(state); |
1785 | return nfs4_open_expired(sp, state); | 1824 | if (status != NFS_OK) |
1825 | status = nfs4_open_expired(sp, state); | ||
1826 | return status; | ||
1786 | } | 1827 | } |
1787 | #endif | 1828 | #endif |
1788 | 1829 | ||
@@ -2375,11 +2416,15 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2375 | int i, len, status = 0; | 2416 | int i, len, status = 0; |
2376 | rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS]; | 2417 | rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS]; |
2377 | 2418 | ||
2378 | len = gss_mech_list_pseudoflavors(&flav_array[0]); | 2419 | len = rpcauth_list_flavors(flav_array, ARRAY_SIZE(flav_array)); |
2379 | flav_array[len] = RPC_AUTH_NULL; | 2420 | BUG_ON(len < 0); |
2380 | len += 1; | ||
2381 | 2421 | ||
2382 | for (i = 0; i < len; i++) { | 2422 | for (i = 0; i < len; i++) { |
2423 | /* AUTH_UNIX is the default flavor if none was specified, | ||
2424 | * thus has already been tried. */ | ||
2425 | if (flav_array[i] == RPC_AUTH_UNIX) | ||
2426 | continue; | ||
2427 | |||
2383 | status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]); | 2428 | status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]); |
2384 | if (status == -NFS4ERR_WRONGSEC || status == -EACCES) | 2429 | if (status == -NFS4ERR_WRONGSEC || status == -EACCES) |
2385 | continue; | 2430 | continue; |
@@ -2766,9 +2811,7 @@ static int nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry) | |||
2766 | * | 2811 | * |
2767 | * In the case of WRITE, we also want to put the GETATTR after | 2812 | * In the case of WRITE, we also want to put the GETATTR after |
2768 | * the operation -- in this case because we want to make sure | 2813 | * the operation -- in this case because we want to make sure |
2769 | * we get the post-operation mtime and size. This means that | 2814 | * we get the post-operation mtime and size. |
2770 | * we can't use xdr_encode_pages() as written: we need a variant | ||
2771 | * of it which would leave room in the 'tail' iovec. | ||
2772 | * | 2815 | * |
2773 | * Both of these changes to the XDR layer would in fact be quite | 2816 | * Both of these changes to the XDR layer would in fact be quite |
2774 | * minor, but I decided to leave them for a subsequent patch. | 2817 | * minor, but I decided to leave them for a subsequent patch. |
@@ -2821,7 +2864,9 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
2821 | return PTR_ERR(ctx); | 2864 | return PTR_ERR(ctx); |
2822 | 2865 | ||
2823 | sattr->ia_mode &= ~current_umask(); | 2866 | sattr->ia_mode &= ~current_umask(); |
2824 | state = nfs4_do_open(dir, dentry, ctx->mode, flags, sattr, ctx->cred, NULL); | 2867 | state = nfs4_do_open(dir, dentry, ctx->mode, |
2868 | flags, sattr, ctx->cred, | ||
2869 | &ctx->mdsthreshold); | ||
2825 | d_drop(dentry); | 2870 | d_drop(dentry); |
2826 | if (IS_ERR(state)) { | 2871 | if (IS_ERR(state)) { |
2827 | status = PTR_ERR(state); | 2872 | status = PTR_ERR(state); |
@@ -3315,8 +3360,14 @@ static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, str | |||
3315 | 3360 | ||
3316 | static int nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) | 3361 | static int nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) |
3317 | { | 3362 | { |
3363 | int error; | ||
3364 | |||
3318 | nfs_fattr_init(fsinfo->fattr); | 3365 | nfs_fattr_init(fsinfo->fattr); |
3319 | return nfs4_do_fsinfo(server, fhandle, fsinfo); | 3366 | error = nfs4_do_fsinfo(server, fhandle, fsinfo); |
3367 | if (error == 0) | ||
3368 | set_pnfs_layoutdriver(server, fhandle, fsinfo->layouttype); | ||
3369 | |||
3370 | return error; | ||
3320 | } | 3371 | } |
3321 | 3372 | ||
3322 | static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, | 3373 | static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, |
@@ -3443,7 +3494,7 @@ bool nfs4_write_need_cache_consistency_data(const struct nfs_write_data *data) | |||
3443 | /* Otherwise, request attributes if and only if we don't hold | 3494 | /* Otherwise, request attributes if and only if we don't hold |
3444 | * a delegation | 3495 | * a delegation |
3445 | */ | 3496 | */ |
3446 | return nfs_have_delegation(hdr->inode, FMODE_READ) == 0; | 3497 | return nfs4_have_delegation(hdr->inode, FMODE_READ) == 0; |
3447 | } | 3498 | } |
3448 | 3499 | ||
3449 | static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_message *msg) | 3500 | static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_message *msg) |
@@ -3732,7 +3783,8 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
3732 | .rpc_argp = &args, | 3783 | .rpc_argp = &args, |
3733 | .rpc_resp = &res, | 3784 | .rpc_resp = &res, |
3734 | }; | 3785 | }; |
3735 | int ret = -ENOMEM, npages, i, acl_len = 0; | 3786 | int ret = -ENOMEM, npages, i; |
3787 | size_t acl_len = 0; | ||
3736 | 3788 | ||
3737 | npages = (buflen + PAGE_SIZE - 1) >> PAGE_SHIFT; | 3789 | npages = (buflen + PAGE_SIZE - 1) >> PAGE_SHIFT; |
3738 | /* As long as we're doing a round trip to the server anyway, | 3790 | /* As long as we're doing a round trip to the server anyway, |
@@ -3847,7 +3899,7 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl | |||
3847 | i = buf_to_pages_noslab(buf, buflen, arg.acl_pages, &arg.acl_pgbase); | 3899 | i = buf_to_pages_noslab(buf, buflen, arg.acl_pages, &arg.acl_pgbase); |
3848 | if (i < 0) | 3900 | if (i < 0) |
3849 | return i; | 3901 | return i; |
3850 | nfs_inode_return_delegation(inode); | 3902 | nfs4_inode_return_delegation(inode); |
3851 | ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); | 3903 | ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); |
3852 | 3904 | ||
3853 | /* | 3905 | /* |
@@ -3961,6 +4013,16 @@ static void nfs4_init_boot_verifier(const struct nfs_client *clp, | |||
3961 | memcpy(bootverf->data, verf, sizeof(bootverf->data)); | 4013 | memcpy(bootverf->data, verf, sizeof(bootverf->data)); |
3962 | } | 4014 | } |
3963 | 4015 | ||
4016 | /** | ||
4017 | * nfs4_proc_setclientid - Negotiate client ID | ||
4018 | * @clp: state data structure | ||
4019 | * @program: RPC program for NFSv4 callback service | ||
4020 | * @port: IP port number for NFS4 callback service | ||
4021 | * @cred: RPC credential to use for this call | ||
4022 | * @res: where to place the result | ||
4023 | * | ||
4024 | * Returns zero, a negative errno, or a negative NFS4ERR status code. | ||
4025 | */ | ||
3964 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, | 4026 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, |
3965 | unsigned short port, struct rpc_cred *cred, | 4027 | unsigned short port, struct rpc_cred *cred, |
3966 | struct nfs4_setclientid_res *res) | 4028 | struct nfs4_setclientid_res *res) |
@@ -3977,44 +4039,44 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, | |||
3977 | .rpc_resp = res, | 4039 | .rpc_resp = res, |
3978 | .rpc_cred = cred, | 4040 | .rpc_cred = cred, |
3979 | }; | 4041 | }; |
3980 | int loop = 0; | ||
3981 | int status; | 4042 | int status; |
3982 | 4043 | ||
4044 | /* nfs_client_id4 */ | ||
3983 | nfs4_init_boot_verifier(clp, &sc_verifier); | 4045 | nfs4_init_boot_verifier(clp, &sc_verifier); |
3984 | 4046 | rcu_read_lock(); | |
3985 | for(;;) { | 4047 | setclientid.sc_name_len = scnprintf(setclientid.sc_name, |
3986 | rcu_read_lock(); | 4048 | sizeof(setclientid.sc_name), "%s/%s %s", |
3987 | setclientid.sc_name_len = scnprintf(setclientid.sc_name, | 4049 | clp->cl_ipaddr, |
3988 | sizeof(setclientid.sc_name), "%s/%s %s %s %u", | 4050 | rpc_peeraddr2str(clp->cl_rpcclient, |
3989 | clp->cl_ipaddr, | 4051 | RPC_DISPLAY_ADDR), |
3990 | rpc_peeraddr2str(clp->cl_rpcclient, | 4052 | rpc_peeraddr2str(clp->cl_rpcclient, |
3991 | RPC_DISPLAY_ADDR), | 4053 | RPC_DISPLAY_PROTO)); |
3992 | rpc_peeraddr2str(clp->cl_rpcclient, | 4054 | /* cb_client4 */ |
3993 | RPC_DISPLAY_PROTO), | 4055 | setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, |
3994 | clp->cl_rpcclient->cl_auth->au_ops->au_name, | ||
3995 | clp->cl_id_uniquifier); | ||
3996 | setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, | ||
3997 | sizeof(setclientid.sc_netid), | 4056 | sizeof(setclientid.sc_netid), |
3998 | rpc_peeraddr2str(clp->cl_rpcclient, | 4057 | rpc_peeraddr2str(clp->cl_rpcclient, |
3999 | RPC_DISPLAY_NETID)); | 4058 | RPC_DISPLAY_NETID)); |
4000 | setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr, | 4059 | rcu_read_unlock(); |
4060 | setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr, | ||
4001 | sizeof(setclientid.sc_uaddr), "%s.%u.%u", | 4061 | sizeof(setclientid.sc_uaddr), "%s.%u.%u", |
4002 | clp->cl_ipaddr, port >> 8, port & 255); | 4062 | clp->cl_ipaddr, port >> 8, port & 255); |
4003 | rcu_read_unlock(); | ||
4004 | 4063 | ||
4005 | status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); | 4064 | dprintk("NFS call setclientid auth=%s, '%.*s'\n", |
4006 | if (status != -NFS4ERR_CLID_INUSE) | 4065 | clp->cl_rpcclient->cl_auth->au_ops->au_name, |
4007 | break; | 4066 | setclientid.sc_name_len, setclientid.sc_name); |
4008 | if (loop != 0) { | 4067 | status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); |
4009 | ++clp->cl_id_uniquifier; | 4068 | dprintk("NFS reply setclientid: %d\n", status); |
4010 | break; | ||
4011 | } | ||
4012 | ++loop; | ||
4013 | ssleep(clp->cl_lease_time / HZ + 1); | ||
4014 | } | ||
4015 | return status; | 4069 | return status; |
4016 | } | 4070 | } |
4017 | 4071 | ||
4072 | /** | ||
4073 | * nfs4_proc_setclientid_confirm - Confirm client ID | ||
4074 | * @clp: state data structure | ||
4075 | * @res: result of a previous SETCLIENTID | ||
4076 | * @cred: RPC credential to use for this call | ||
4077 | * | ||
4078 | * Returns zero, a negative errno, or a negative NFS4ERR status code. | ||
4079 | */ | ||
4018 | int nfs4_proc_setclientid_confirm(struct nfs_client *clp, | 4080 | int nfs4_proc_setclientid_confirm(struct nfs_client *clp, |
4019 | struct nfs4_setclientid_res *arg, | 4081 | struct nfs4_setclientid_res *arg, |
4020 | struct rpc_cred *cred) | 4082 | struct rpc_cred *cred) |
@@ -4029,6 +4091,9 @@ int nfs4_proc_setclientid_confirm(struct nfs_client *clp, | |||
4029 | unsigned long now; | 4091 | unsigned long now; |
4030 | int status; | 4092 | int status; |
4031 | 4093 | ||
4094 | dprintk("NFS call setclientid_confirm auth=%s, (client ID %llx)\n", | ||
4095 | clp->cl_rpcclient->cl_auth->au_ops->au_name, | ||
4096 | clp->cl_clientid); | ||
4032 | now = jiffies; | 4097 | now = jiffies; |
4033 | status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); | 4098 | status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); |
4034 | if (status == 0) { | 4099 | if (status == 0) { |
@@ -4037,6 +4102,7 @@ int nfs4_proc_setclientid_confirm(struct nfs_client *clp, | |||
4037 | clp->cl_last_renewal = now; | 4102 | clp->cl_last_renewal = now; |
4038 | spin_unlock(&clp->cl_lock); | 4103 | spin_unlock(&clp->cl_lock); |
4039 | } | 4104 | } |
4105 | dprintk("NFS reply setclientid_confirm: %d\n", status); | ||
4040 | return status; | 4106 | return status; |
4041 | } | 4107 | } |
4042 | 4108 | ||
@@ -4681,9 +4747,17 @@ out: | |||
4681 | } | 4747 | } |
4682 | 4748 | ||
4683 | #if defined(CONFIG_NFS_V4_1) | 4749 | #if defined(CONFIG_NFS_V4_1) |
4750 | /** | ||
4751 | * nfs41_check_expired_locks - possibly free a lock stateid | ||
4752 | * | ||
4753 | * @state: NFSv4 state for an inode | ||
4754 | * | ||
4755 | * Returns NFS_OK if recovery for this stateid is now finished. | ||
4756 | * Otherwise a negative NFS4ERR value is returned. | ||
4757 | */ | ||
4684 | static int nfs41_check_expired_locks(struct nfs4_state *state) | 4758 | static int nfs41_check_expired_locks(struct nfs4_state *state) |
4685 | { | 4759 | { |
4686 | int status, ret = NFS_OK; | 4760 | int status, ret = -NFS4ERR_BAD_STATEID; |
4687 | struct nfs4_lock_state *lsp; | 4761 | struct nfs4_lock_state *lsp; |
4688 | struct nfs_server *server = NFS_SERVER(state->inode); | 4762 | struct nfs_server *server = NFS_SERVER(state->inode); |
4689 | 4763 | ||
@@ -4691,7 +4765,11 @@ static int nfs41_check_expired_locks(struct nfs4_state *state) | |||
4691 | if (lsp->ls_flags & NFS_LOCK_INITIALIZED) { | 4765 | if (lsp->ls_flags & NFS_LOCK_INITIALIZED) { |
4692 | status = nfs41_test_stateid(server, &lsp->ls_stateid); | 4766 | status = nfs41_test_stateid(server, &lsp->ls_stateid); |
4693 | if (status != NFS_OK) { | 4767 | if (status != NFS_OK) { |
4694 | nfs41_free_stateid(server, &lsp->ls_stateid); | 4768 | /* Free the stateid unless the server |
4769 | * informs us the stateid is unrecognized. */ | ||
4770 | if (status != -NFS4ERR_BAD_STATEID) | ||
4771 | nfs41_free_stateid(server, | ||
4772 | &lsp->ls_stateid); | ||
4695 | lsp->ls_flags &= ~NFS_LOCK_INITIALIZED; | 4773 | lsp->ls_flags &= ~NFS_LOCK_INITIALIZED; |
4696 | ret = status; | 4774 | ret = status; |
4697 | } | 4775 | } |
@@ -4707,9 +4785,9 @@ static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *reques | |||
4707 | 4785 | ||
4708 | if (test_bit(LK_STATE_IN_USE, &state->flags)) | 4786 | if (test_bit(LK_STATE_IN_USE, &state->flags)) |
4709 | status = nfs41_check_expired_locks(state); | 4787 | status = nfs41_check_expired_locks(state); |
4710 | if (status == NFS_OK) | 4788 | if (status != NFS_OK) |
4711 | return status; | 4789 | status = nfs4_lock_expired(state, request); |
4712 | return nfs4_lock_expired(state, request); | 4790 | return status; |
4713 | } | 4791 | } |
4714 | #endif | 4792 | #endif |
4715 | 4793 | ||
@@ -4807,7 +4885,7 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request) | |||
4807 | * Don't rely on the VFS having checked the file open mode, | 4885 | * Don't rely on the VFS having checked the file open mode, |
4808 | * since it won't do this for flock() locks. | 4886 | * since it won't do this for flock() locks. |
4809 | */ | 4887 | */ |
4810 | switch (request->fl_type & (F_RDLCK|F_WRLCK|F_UNLCK)) { | 4888 | switch (request->fl_type) { |
4811 | case F_RDLCK: | 4889 | case F_RDLCK: |
4812 | if (!(filp->f_mode & FMODE_READ)) | 4890 | if (!(filp->f_mode & FMODE_READ)) |
4813 | return -EBADF; | 4891 | return -EBADF; |
@@ -5168,6 +5246,8 @@ out: | |||
5168 | /* | 5246 | /* |
5169 | * nfs4_proc_exchange_id() | 5247 | * nfs4_proc_exchange_id() |
5170 | * | 5248 | * |
5249 | * Returns zero, a negative errno, or a negative NFS4ERR status code. | ||
5250 | * | ||
5171 | * Since the clientid has expired, all compounds using sessions | 5251 | * Since the clientid has expired, all compounds using sessions |
5172 | * associated with the stale clientid will be returning | 5252 | * associated with the stale clientid will be returning |
5173 | * NFS4ERR_BADSESSION in the sequence operation, and will therefore | 5253 | * NFS4ERR_BADSESSION in the sequence operation, and will therefore |
@@ -5192,16 +5272,14 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | |||
5192 | .rpc_cred = cred, | 5272 | .rpc_cred = cred, |
5193 | }; | 5273 | }; |
5194 | 5274 | ||
5195 | dprintk("--> %s\n", __func__); | ||
5196 | BUG_ON(clp == NULL); | ||
5197 | |||
5198 | nfs4_init_boot_verifier(clp, &verifier); | 5275 | nfs4_init_boot_verifier(clp, &verifier); |
5199 | |||
5200 | args.id_len = scnprintf(args.id, sizeof(args.id), | 5276 | args.id_len = scnprintf(args.id, sizeof(args.id), |
5201 | "%s/%s/%u", | 5277 | "%s/%s", |
5202 | clp->cl_ipaddr, | 5278 | clp->cl_ipaddr, |
5203 | clp->cl_rpcclient->cl_nodename, | 5279 | clp->cl_rpcclient->cl_nodename); |
5204 | clp->cl_rpcclient->cl_auth->au_flavor); | 5280 | dprintk("NFS call exchange_id auth=%s, '%.*s'\n", |
5281 | clp->cl_rpcclient->cl_auth->au_ops->au_name, | ||
5282 | args.id_len, args.id); | ||
5205 | 5283 | ||
5206 | res.server_owner = kzalloc(sizeof(struct nfs41_server_owner), | 5284 | res.server_owner = kzalloc(sizeof(struct nfs41_server_owner), |
5207 | GFP_NOFS); | 5285 | GFP_NOFS); |
@@ -5264,12 +5342,12 @@ out_server_scope: | |||
5264 | kfree(res.server_scope); | 5342 | kfree(res.server_scope); |
5265 | out: | 5343 | out: |
5266 | if (clp->cl_implid != NULL) | 5344 | if (clp->cl_implid != NULL) |
5267 | dprintk("%s: Server Implementation ID: " | 5345 | dprintk("NFS reply exchange_id: Server Implementation ID: " |
5268 | "domain: %s, name: %s, date: %llu,%u\n", | 5346 | "domain: %s, name: %s, date: %llu,%u\n", |
5269 | __func__, clp->cl_implid->domain, clp->cl_implid->name, | 5347 | clp->cl_implid->domain, clp->cl_implid->name, |
5270 | clp->cl_implid->date.seconds, | 5348 | clp->cl_implid->date.seconds, |
5271 | clp->cl_implid->date.nseconds); | 5349 | clp->cl_implid->date.nseconds); |
5272 | dprintk("<-- %s status= %d\n", __func__, status); | 5350 | dprintk("NFS reply exchange_id: %d\n", status); |
5273 | return status; | 5351 | return status; |
5274 | } | 5352 | } |
5275 | 5353 | ||
@@ -6570,22 +6648,36 @@ static int _nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid) | |||
6570 | .rpc_resp = &res, | 6648 | .rpc_resp = &res, |
6571 | }; | 6649 | }; |
6572 | 6650 | ||
6651 | dprintk("NFS call test_stateid %p\n", stateid); | ||
6573 | nfs41_init_sequence(&args.seq_args, &res.seq_res, 0); | 6652 | nfs41_init_sequence(&args.seq_args, &res.seq_res, 0); |
6574 | status = nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 1); | 6653 | status = nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 1); |
6575 | 6654 | if (status != NFS_OK) { | |
6576 | if (status == NFS_OK) | 6655 | dprintk("NFS reply test_stateid: failed, %d\n", status); |
6577 | return res.status; | 6656 | return status; |
6578 | return status; | 6657 | } |
6658 | dprintk("NFS reply test_stateid: succeeded, %d\n", -res.status); | ||
6659 | return -res.status; | ||
6579 | } | 6660 | } |
6580 | 6661 | ||
6662 | /** | ||
6663 | * nfs41_test_stateid - perform a TEST_STATEID operation | ||
6664 | * | ||
6665 | * @server: server / transport on which to perform the operation | ||
6666 | * @stateid: state ID to test | ||
6667 | * | ||
6668 | * Returns NFS_OK if the server recognizes that "stateid" is valid. | ||
6669 | * Otherwise a negative NFS4ERR value is returned if the operation | ||
6670 | * failed or the state ID is not currently valid. | ||
6671 | */ | ||
6581 | static int nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid) | 6672 | static int nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid) |
6582 | { | 6673 | { |
6583 | struct nfs4_exception exception = { }; | 6674 | struct nfs4_exception exception = { }; |
6584 | int err; | 6675 | int err; |
6585 | do { | 6676 | do { |
6586 | err = nfs4_handle_exception(server, | 6677 | err = _nfs41_test_stateid(server, stateid); |
6587 | _nfs41_test_stateid(server, stateid), | 6678 | if (err != -NFS4ERR_DELAY) |
6588 | &exception); | 6679 | break; |
6680 | nfs4_handle_exception(server, err, &exception); | ||
6589 | } while (exception.retry); | 6681 | } while (exception.retry); |
6590 | return err; | 6682 | return err; |
6591 | } | 6683 | } |
@@ -6601,19 +6693,34 @@ static int _nfs4_free_stateid(struct nfs_server *server, nfs4_stateid *stateid) | |||
6601 | .rpc_argp = &args, | 6693 | .rpc_argp = &args, |
6602 | .rpc_resp = &res, | 6694 | .rpc_resp = &res, |
6603 | }; | 6695 | }; |
6696 | int status; | ||
6604 | 6697 | ||
6698 | dprintk("NFS call free_stateid %p\n", stateid); | ||
6605 | nfs41_init_sequence(&args.seq_args, &res.seq_res, 0); | 6699 | nfs41_init_sequence(&args.seq_args, &res.seq_res, 0); |
6606 | return nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 1); | 6700 | status = nfs4_call_sync_sequence(server->client, server, &msg, |
6701 | &args.seq_args, &res.seq_res, 1); | ||
6702 | dprintk("NFS reply free_stateid: %d\n", status); | ||
6703 | return status; | ||
6607 | } | 6704 | } |
6608 | 6705 | ||
6706 | /** | ||
6707 | * nfs41_free_stateid - perform a FREE_STATEID operation | ||
6708 | * | ||
6709 | * @server: server / transport on which to perform the operation | ||
6710 | * @stateid: state ID to release | ||
6711 | * | ||
6712 | * Returns NFS_OK if the server freed "stateid". Otherwise a | ||
6713 | * negative NFS4ERR value is returned. | ||
6714 | */ | ||
6609 | static int nfs41_free_stateid(struct nfs_server *server, nfs4_stateid *stateid) | 6715 | static int nfs41_free_stateid(struct nfs_server *server, nfs4_stateid *stateid) |
6610 | { | 6716 | { |
6611 | struct nfs4_exception exception = { }; | 6717 | struct nfs4_exception exception = { }; |
6612 | int err; | 6718 | int err; |
6613 | do { | 6719 | do { |
6614 | err = nfs4_handle_exception(server, | 6720 | err = _nfs4_free_stateid(server, stateid); |
6615 | _nfs4_free_stateid(server, stateid), | 6721 | if (err != -NFS4ERR_DELAY) |
6616 | &exception); | 6722 | break; |
6723 | nfs4_handle_exception(server, err, &exception); | ||
6617 | } while (exception.retry); | 6724 | } while (exception.retry); |
6618 | return err; | 6725 | return err; |
6619 | } | 6726 | } |
@@ -6725,6 +6832,26 @@ const struct nfs4_minor_version_ops *nfs_v4_minor_ops[] = { | |||
6725 | #endif | 6832 | #endif |
6726 | }; | 6833 | }; |
6727 | 6834 | ||
6835 | const struct inode_operations nfs4_dir_inode_operations = { | ||
6836 | .create = nfs_create, | ||
6837 | .lookup = nfs_lookup, | ||
6838 | .atomic_open = nfs_atomic_open, | ||
6839 | .link = nfs_link, | ||
6840 | .unlink = nfs_unlink, | ||
6841 | .symlink = nfs_symlink, | ||
6842 | .mkdir = nfs_mkdir, | ||
6843 | .rmdir = nfs_rmdir, | ||
6844 | .mknod = nfs_mknod, | ||
6845 | .rename = nfs_rename, | ||
6846 | .permission = nfs_permission, | ||
6847 | .getattr = nfs_getattr, | ||
6848 | .setattr = nfs_setattr, | ||
6849 | .getxattr = generic_getxattr, | ||
6850 | .setxattr = generic_setxattr, | ||
6851 | .listxattr = generic_listxattr, | ||
6852 | .removexattr = generic_removexattr, | ||
6853 | }; | ||
6854 | |||
6728 | static const struct inode_operations nfs4_file_inode_operations = { | 6855 | static const struct inode_operations nfs4_file_inode_operations = { |
6729 | .permission = nfs_permission, | 6856 | .permission = nfs_permission, |
6730 | .getattr = nfs_getattr, | 6857 | .getattr = nfs_getattr, |
@@ -6769,9 +6896,11 @@ const struct nfs_rpc_ops nfs_v4_clientops = { | |||
6769 | .set_capabilities = nfs4_server_capabilities, | 6896 | .set_capabilities = nfs4_server_capabilities, |
6770 | .decode_dirent = nfs4_decode_dirent, | 6897 | .decode_dirent = nfs4_decode_dirent, |
6771 | .read_setup = nfs4_proc_read_setup, | 6898 | .read_setup = nfs4_proc_read_setup, |
6899 | .read_pageio_init = pnfs_pageio_init_read, | ||
6772 | .read_rpc_prepare = nfs4_proc_read_rpc_prepare, | 6900 | .read_rpc_prepare = nfs4_proc_read_rpc_prepare, |
6773 | .read_done = nfs4_read_done, | 6901 | .read_done = nfs4_read_done, |
6774 | .write_setup = nfs4_proc_write_setup, | 6902 | .write_setup = nfs4_proc_write_setup, |
6903 | .write_pageio_init = pnfs_pageio_init_write, | ||
6775 | .write_rpc_prepare = nfs4_proc_write_rpc_prepare, | 6904 | .write_rpc_prepare = nfs4_proc_write_rpc_prepare, |
6776 | .write_done = nfs4_write_done, | 6905 | .write_done = nfs4_write_done, |
6777 | .commit_setup = nfs4_proc_commit_setup, | 6906 | .commit_setup = nfs4_proc_commit_setup, |
@@ -6781,7 +6910,11 @@ const struct nfs_rpc_ops nfs_v4_clientops = { | |||
6781 | .clear_acl_cache = nfs4_zap_acl_attr, | 6910 | .clear_acl_cache = nfs4_zap_acl_attr, |
6782 | .close_context = nfs4_close_context, | 6911 | .close_context = nfs4_close_context, |
6783 | .open_context = nfs4_atomic_open, | 6912 | .open_context = nfs4_atomic_open, |
6913 | .have_delegation = nfs4_have_delegation, | ||
6914 | .return_delegation = nfs4_inode_return_delegation, | ||
6915 | .alloc_client = nfs4_alloc_client, | ||
6784 | .init_client = nfs4_init_client, | 6916 | .init_client = nfs4_init_client, |
6917 | .free_client = nfs4_free_client, | ||
6785 | }; | 6918 | }; |
6786 | 6919 | ||
6787 | static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = { | 6920 | static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = { |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index f38300e9f171..55148def5540 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -1606,10 +1606,15 @@ static int nfs4_handle_reclaim_lease_error(struct nfs_client *clp, int status) | |||
1606 | return -ESERVERFAULT; | 1606 | return -ESERVERFAULT; |
1607 | /* Lease confirmation error: retry after purging the lease */ | 1607 | /* Lease confirmation error: retry after purging the lease */ |
1608 | ssleep(1); | 1608 | ssleep(1); |
1609 | case -NFS4ERR_CLID_INUSE: | ||
1610 | case -NFS4ERR_STALE_CLIENTID: | 1609 | case -NFS4ERR_STALE_CLIENTID: |
1611 | clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); | 1610 | clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); |
1612 | break; | 1611 | break; |
1612 | case -NFS4ERR_CLID_INUSE: | ||
1613 | pr_err("NFS: Server %s reports our clientid is in use\n", | ||
1614 | clp->cl_hostname); | ||
1615 | nfs_mark_client_ready(clp, -EPERM); | ||
1616 | clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); | ||
1617 | return -EPERM; | ||
1613 | case -EACCES: | 1618 | case -EACCES: |
1614 | if (clp->cl_machine_cred == NULL) | 1619 | if (clp->cl_machine_cred == NULL) |
1615 | return -EACCES; | 1620 | return -EACCES; |
@@ -1642,7 +1647,7 @@ static int nfs4_handle_reclaim_lease_error(struct nfs_client *clp, int status) | |||
1642 | return 0; | 1647 | return 0; |
1643 | } | 1648 | } |
1644 | 1649 | ||
1645 | static int nfs4_reclaim_lease(struct nfs_client *clp) | 1650 | static int nfs4_establish_lease(struct nfs_client *clp) |
1646 | { | 1651 | { |
1647 | struct rpc_cred *cred; | 1652 | struct rpc_cred *cred; |
1648 | const struct nfs4_state_recovery_ops *ops = | 1653 | const struct nfs4_state_recovery_ops *ops = |
@@ -1655,7 +1660,41 @@ static int nfs4_reclaim_lease(struct nfs_client *clp) | |||
1655 | status = ops->establish_clid(clp, cred); | 1660 | status = ops->establish_clid(clp, cred); |
1656 | put_rpccred(cred); | 1661 | put_rpccred(cred); |
1657 | if (status != 0) | 1662 | if (status != 0) |
1663 | return status; | ||
1664 | pnfs_destroy_all_layouts(clp); | ||
1665 | return 0; | ||
1666 | } | ||
1667 | |||
1668 | /* | ||
1669 | * Returns zero or a negative errno. NFS4ERR values are converted | ||
1670 | * to local errno values. | ||
1671 | */ | ||
1672 | static int nfs4_reclaim_lease(struct nfs_client *clp) | ||
1673 | { | ||
1674 | int status; | ||
1675 | |||
1676 | status = nfs4_establish_lease(clp); | ||
1677 | if (status < 0) | ||
1678 | return nfs4_handle_reclaim_lease_error(clp, status); | ||
1679 | if (test_and_clear_bit(NFS4CLNT_SERVER_SCOPE_MISMATCH, &clp->cl_state)) | ||
1680 | nfs4_state_start_reclaim_nograce(clp); | ||
1681 | if (!test_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) | ||
1682 | set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state); | ||
1683 | clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); | ||
1684 | clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
1685 | return 0; | ||
1686 | } | ||
1687 | |||
1688 | static int nfs4_purge_lease(struct nfs_client *clp) | ||
1689 | { | ||
1690 | int status; | ||
1691 | |||
1692 | status = nfs4_establish_lease(clp); | ||
1693 | if (status < 0) | ||
1658 | return nfs4_handle_reclaim_lease_error(clp, status); | 1694 | return nfs4_handle_reclaim_lease_error(clp, status); |
1695 | clear_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state); | ||
1696 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
1697 | nfs4_state_start_reclaim_nograce(clp); | ||
1659 | return 0; | 1698 | return 0; |
1660 | } | 1699 | } |
1661 | 1700 | ||
@@ -1764,6 +1803,8 @@ static int nfs4_reset_session(struct nfs_client *clp) | |||
1764 | struct rpc_cred *cred; | 1803 | struct rpc_cred *cred; |
1765 | int status; | 1804 | int status; |
1766 | 1805 | ||
1806 | if (!nfs4_has_session(clp)) | ||
1807 | return 0; | ||
1767 | nfs4_begin_drain_session(clp); | 1808 | nfs4_begin_drain_session(clp); |
1768 | cred = nfs4_get_exchange_id_cred(clp); | 1809 | cred = nfs4_get_exchange_id_cred(clp); |
1769 | status = nfs4_proc_destroy_session(clp->cl_session, cred); | 1810 | status = nfs4_proc_destroy_session(clp->cl_session, cred); |
@@ -1792,12 +1833,14 @@ out: | |||
1792 | 1833 | ||
1793 | static int nfs4_recall_slot(struct nfs_client *clp) | 1834 | static int nfs4_recall_slot(struct nfs_client *clp) |
1794 | { | 1835 | { |
1795 | struct nfs4_slot_table *fc_tbl = &clp->cl_session->fc_slot_table; | 1836 | struct nfs4_slot_table *fc_tbl; |
1796 | struct nfs4_channel_attrs *fc_attrs = &clp->cl_session->fc_attrs; | ||
1797 | struct nfs4_slot *new, *old; | 1837 | struct nfs4_slot *new, *old; |
1798 | int i; | 1838 | int i; |
1799 | 1839 | ||
1840 | if (!nfs4_has_session(clp)) | ||
1841 | return 0; | ||
1800 | nfs4_begin_drain_session(clp); | 1842 | nfs4_begin_drain_session(clp); |
1843 | fc_tbl = &clp->cl_session->fc_slot_table; | ||
1801 | new = kmalloc(fc_tbl->target_max_slots * sizeof(struct nfs4_slot), | 1844 | new = kmalloc(fc_tbl->target_max_slots * sizeof(struct nfs4_slot), |
1802 | GFP_NOFS); | 1845 | GFP_NOFS); |
1803 | if (!new) | 1846 | if (!new) |
@@ -1810,11 +1853,10 @@ static int nfs4_recall_slot(struct nfs_client *clp) | |||
1810 | fc_tbl->slots = new; | 1853 | fc_tbl->slots = new; |
1811 | fc_tbl->max_slots = fc_tbl->target_max_slots; | 1854 | fc_tbl->max_slots = fc_tbl->target_max_slots; |
1812 | fc_tbl->target_max_slots = 0; | 1855 | fc_tbl->target_max_slots = 0; |
1813 | fc_attrs->max_reqs = fc_tbl->max_slots; | 1856 | clp->cl_session->fc_attrs.max_reqs = fc_tbl->max_slots; |
1814 | spin_unlock(&fc_tbl->slot_tbl_lock); | 1857 | spin_unlock(&fc_tbl->slot_tbl_lock); |
1815 | 1858 | ||
1816 | kfree(old); | 1859 | kfree(old); |
1817 | nfs4_end_drain_session(clp); | ||
1818 | return 0; | 1860 | return 0; |
1819 | } | 1861 | } |
1820 | 1862 | ||
@@ -1823,6 +1865,8 @@ static int nfs4_bind_conn_to_session(struct nfs_client *clp) | |||
1823 | struct rpc_cred *cred; | 1865 | struct rpc_cred *cred; |
1824 | int ret; | 1866 | int ret; |
1825 | 1867 | ||
1868 | if (!nfs4_has_session(clp)) | ||
1869 | return 0; | ||
1826 | nfs4_begin_drain_session(clp); | 1870 | nfs4_begin_drain_session(clp); |
1827 | cred = nfs4_get_exchange_id_cred(clp); | 1871 | cred = nfs4_get_exchange_id_cred(clp); |
1828 | ret = nfs4_proc_bind_conn_to_session(clp, cred); | 1872 | ret = nfs4_proc_bind_conn_to_session(clp, cred); |
@@ -1857,37 +1901,29 @@ static int nfs4_bind_conn_to_session(struct nfs_client *clp) | |||
1857 | static void nfs4_state_manager(struct nfs_client *clp) | 1901 | static void nfs4_state_manager(struct nfs_client *clp) |
1858 | { | 1902 | { |
1859 | int status = 0; | 1903 | int status = 0; |
1904 | const char *section = "", *section_sep = ""; | ||
1860 | 1905 | ||
1861 | /* Ensure exclusive access to NFSv4 state */ | 1906 | /* Ensure exclusive access to NFSv4 state */ |
1862 | do { | 1907 | do { |
1863 | if (test_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state)) { | 1908 | if (test_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state)) { |
1864 | status = nfs4_reclaim_lease(clp); | 1909 | section = "purge state"; |
1910 | status = nfs4_purge_lease(clp); | ||
1865 | if (status < 0) | 1911 | if (status < 0) |
1866 | goto out_error; | 1912 | goto out_error; |
1867 | clear_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state); | 1913 | continue; |
1868 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
1869 | } | 1914 | } |
1870 | 1915 | ||
1871 | if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) { | 1916 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) { |
1917 | section = "lease expired"; | ||
1872 | /* We're going to have to re-establish a clientid */ | 1918 | /* We're going to have to re-establish a clientid */ |
1873 | status = nfs4_reclaim_lease(clp); | 1919 | status = nfs4_reclaim_lease(clp); |
1874 | if (status < 0) | 1920 | if (status < 0) |
1875 | goto out_error; | 1921 | goto out_error; |
1876 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) | 1922 | continue; |
1877 | continue; | ||
1878 | clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); | ||
1879 | |||
1880 | if (test_and_clear_bit(NFS4CLNT_SERVER_SCOPE_MISMATCH, | ||
1881 | &clp->cl_state)) | ||
1882 | nfs4_state_start_reclaim_nograce(clp); | ||
1883 | else | ||
1884 | set_bit(NFS4CLNT_RECLAIM_REBOOT, | ||
1885 | &clp->cl_state); | ||
1886 | |||
1887 | pnfs_destroy_all_layouts(clp); | ||
1888 | } | 1923 | } |
1889 | 1924 | ||
1890 | if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) { | 1925 | if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) { |
1926 | section = "check lease"; | ||
1891 | status = nfs4_check_lease(clp); | 1927 | status = nfs4_check_lease(clp); |
1892 | if (status < 0) | 1928 | if (status < 0) |
1893 | goto out_error; | 1929 | goto out_error; |
@@ -1896,8 +1932,8 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1896 | } | 1932 | } |
1897 | 1933 | ||
1898 | /* Initialize or reset the session */ | 1934 | /* Initialize or reset the session */ |
1899 | if (test_and_clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) | 1935 | if (test_and_clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)) { |
1900 | && nfs4_has_session(clp)) { | 1936 | section = "reset session"; |
1901 | status = nfs4_reset_session(clp); | 1937 | status = nfs4_reset_session(clp); |
1902 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) | 1938 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) |
1903 | continue; | 1939 | continue; |
@@ -1907,15 +1943,26 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1907 | 1943 | ||
1908 | /* Send BIND_CONN_TO_SESSION */ | 1944 | /* Send BIND_CONN_TO_SESSION */ |
1909 | if (test_and_clear_bit(NFS4CLNT_BIND_CONN_TO_SESSION, | 1945 | if (test_and_clear_bit(NFS4CLNT_BIND_CONN_TO_SESSION, |
1910 | &clp->cl_state) && nfs4_has_session(clp)) { | 1946 | &clp->cl_state)) { |
1947 | section = "bind conn to session"; | ||
1911 | status = nfs4_bind_conn_to_session(clp); | 1948 | status = nfs4_bind_conn_to_session(clp); |
1912 | if (status < 0) | 1949 | if (status < 0) |
1913 | goto out_error; | 1950 | goto out_error; |
1914 | continue; | 1951 | continue; |
1915 | } | 1952 | } |
1916 | 1953 | ||
1954 | /* Recall session slots */ | ||
1955 | if (test_and_clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state)) { | ||
1956 | section = "recall slot"; | ||
1957 | status = nfs4_recall_slot(clp); | ||
1958 | if (status < 0) | ||
1959 | goto out_error; | ||
1960 | continue; | ||
1961 | } | ||
1962 | |||
1917 | /* First recover reboot state... */ | 1963 | /* First recover reboot state... */ |
1918 | if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) { | 1964 | if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) { |
1965 | section = "reclaim reboot"; | ||
1919 | status = nfs4_do_reclaim(clp, | 1966 | status = nfs4_do_reclaim(clp, |
1920 | clp->cl_mvops->reboot_recovery_ops); | 1967 | clp->cl_mvops->reboot_recovery_ops); |
1921 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) || | 1968 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) || |
@@ -1930,6 +1977,7 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1930 | 1977 | ||
1931 | /* Now recover expired state... */ | 1978 | /* Now recover expired state... */ |
1932 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) { | 1979 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) { |
1980 | section = "reclaim nograce"; | ||
1933 | status = nfs4_do_reclaim(clp, | 1981 | status = nfs4_do_reclaim(clp, |
1934 | clp->cl_mvops->nograce_recovery_ops); | 1982 | clp->cl_mvops->nograce_recovery_ops); |
1935 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) || | 1983 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) || |
@@ -1945,15 +1993,6 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1945 | nfs_client_return_marked_delegations(clp); | 1993 | nfs_client_return_marked_delegations(clp); |
1946 | continue; | 1994 | continue; |
1947 | } | 1995 | } |
1948 | /* Recall session slots */ | ||
1949 | if (test_and_clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state) | ||
1950 | && nfs4_has_session(clp)) { | ||
1951 | status = nfs4_recall_slot(clp); | ||
1952 | if (status < 0) | ||
1953 | goto out_error; | ||
1954 | continue; | ||
1955 | } | ||
1956 | |||
1957 | 1996 | ||
1958 | nfs4_clear_state_manager_bit(clp); | 1997 | nfs4_clear_state_manager_bit(clp); |
1959 | /* Did we race with an attempt to give us more work? */ | 1998 | /* Did we race with an attempt to give us more work? */ |
@@ -1964,8 +2003,11 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1964 | } while (atomic_read(&clp->cl_count) > 1); | 2003 | } while (atomic_read(&clp->cl_count) > 1); |
1965 | return; | 2004 | return; |
1966 | out_error: | 2005 | out_error: |
1967 | pr_warn_ratelimited("NFS: state manager failed on NFSv4 server %s" | 2006 | if (strlen(section)) |
1968 | " with error %d\n", clp->cl_hostname, -status); | 2007 | section_sep = ": "; |
2008 | pr_warn_ratelimited("NFS: state manager%s%s failed on NFSv4 server %s" | ||
2009 | " with error %d\n", section_sep, section, | ||
2010 | clp->cl_hostname, -status); | ||
1969 | nfs4_end_drain_session(clp); | 2011 | nfs4_end_drain_session(clp); |
1970 | nfs4_clear_state_manager_bit(clp); | 2012 | nfs4_clear_state_manager_bit(clp); |
1971 | } | 2013 | } |
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c new file mode 100644 index 000000000000..59264fb335c8 --- /dev/null +++ b/fs/nfs/nfs4super.c | |||
@@ -0,0 +1,360 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Bryan Schumaker <bjschuma@netapp.com> | ||
3 | */ | ||
4 | #include <linux/init.h> | ||
5 | #include <linux/module.h> | ||
6 | #include <linux/nfs_idmap.h> | ||
7 | #include <linux/nfs4_mount.h> | ||
8 | #include <linux/nfs_fs.h> | ||
9 | #include "internal.h" | ||
10 | #include "nfs4_fs.h" | ||
11 | |||
12 | #define NFSDBG_FACILITY NFSDBG_VFS | ||
13 | |||
14 | static struct dentry *nfs4_remote_mount(struct file_system_type *fs_type, | ||
15 | int flags, const char *dev_name, void *raw_data); | ||
16 | static struct dentry *nfs4_xdev_mount(struct file_system_type *fs_type, | ||
17 | int flags, const char *dev_name, void *raw_data); | ||
18 | static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type, | ||
19 | int flags, const char *dev_name, void *raw_data); | ||
20 | static struct dentry *nfs4_remote_referral_mount(struct file_system_type *fs_type, | ||
21 | int flags, const char *dev_name, void *raw_data); | ||
22 | |||
23 | static struct file_system_type nfs4_fs_type = { | ||
24 | .owner = THIS_MODULE, | ||
25 | .name = "nfs4", | ||
26 | .mount = nfs_fs_mount, | ||
27 | .kill_sb = nfs_kill_super, | ||
28 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
29 | }; | ||
30 | |||
31 | static struct file_system_type nfs4_remote_fs_type = { | ||
32 | .owner = THIS_MODULE, | ||
33 | .name = "nfs4", | ||
34 | .mount = nfs4_remote_mount, | ||
35 | .kill_sb = nfs_kill_super, | ||
36 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
37 | }; | ||
38 | |||
39 | struct file_system_type nfs4_xdev_fs_type = { | ||
40 | .owner = THIS_MODULE, | ||
41 | .name = "nfs4", | ||
42 | .mount = nfs4_xdev_mount, | ||
43 | .kill_sb = nfs_kill_super, | ||
44 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
45 | }; | ||
46 | |||
47 | static struct file_system_type nfs4_remote_referral_fs_type = { | ||
48 | .owner = THIS_MODULE, | ||
49 | .name = "nfs4", | ||
50 | .mount = nfs4_remote_referral_mount, | ||
51 | .kill_sb = nfs_kill_super, | ||
52 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
53 | }; | ||
54 | |||
55 | struct file_system_type nfs4_referral_fs_type = { | ||
56 | .owner = THIS_MODULE, | ||
57 | .name = "nfs4", | ||
58 | .mount = nfs4_referral_mount, | ||
59 | .kill_sb = nfs_kill_super, | ||
60 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
61 | }; | ||
62 | |||
63 | static const struct super_operations nfs4_sops = { | ||
64 | .alloc_inode = nfs_alloc_inode, | ||
65 | .destroy_inode = nfs_destroy_inode, | ||
66 | .write_inode = nfs4_write_inode, | ||
67 | .put_super = nfs_put_super, | ||
68 | .statfs = nfs_statfs, | ||
69 | .evict_inode = nfs4_evict_inode, | ||
70 | .umount_begin = nfs_umount_begin, | ||
71 | .show_options = nfs_show_options, | ||
72 | .show_devname = nfs_show_devname, | ||
73 | .show_path = nfs_show_path, | ||
74 | .show_stats = nfs_show_stats, | ||
75 | .remount_fs = nfs_remount, | ||
76 | }; | ||
77 | |||
78 | /* | ||
79 | * Set up an NFS4 superblock | ||
80 | */ | ||
81 | static void nfs4_fill_super(struct super_block *sb, | ||
82 | struct nfs_mount_info *mount_info) | ||
83 | { | ||
84 | sb->s_time_gran = 1; | ||
85 | sb->s_op = &nfs4_sops; | ||
86 | /* | ||
87 | * The VFS shouldn't apply the umask to mode bits. We will do | ||
88 | * so ourselves when necessary. | ||
89 | */ | ||
90 | sb->s_flags |= MS_POSIXACL; | ||
91 | sb->s_xattr = nfs4_xattr_handlers; | ||
92 | nfs_initialise_sb(sb); | ||
93 | } | ||
94 | |||
95 | /* | ||
96 | * Get the superblock for the NFS4 root partition | ||
97 | */ | ||
98 | static struct dentry * | ||
99 | nfs4_remote_mount(struct file_system_type *fs_type, int flags, | ||
100 | const char *dev_name, void *info) | ||
101 | { | ||
102 | struct nfs_mount_info *mount_info = info; | ||
103 | struct nfs_server *server; | ||
104 | struct dentry *mntroot = ERR_PTR(-ENOMEM); | ||
105 | |||
106 | mount_info->fill_super = nfs4_fill_super; | ||
107 | mount_info->set_security = nfs_set_sb_security; | ||
108 | |||
109 | /* Get a volume representation */ | ||
110 | server = nfs4_create_server(mount_info->parsed, mount_info->mntfh); | ||
111 | if (IS_ERR(server)) { | ||
112 | mntroot = ERR_CAST(server); | ||
113 | goto out; | ||
114 | } | ||
115 | |||
116 | mntroot = nfs_fs_mount_common(fs_type, server, flags, dev_name, mount_info); | ||
117 | |||
118 | out: | ||
119 | return mntroot; | ||
120 | } | ||
121 | |||
122 | static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type, | ||
123 | int flags, void *data, const char *hostname) | ||
124 | { | ||
125 | struct vfsmount *root_mnt; | ||
126 | char *root_devname; | ||
127 | size_t len; | ||
128 | |||
129 | len = strlen(hostname) + 5; | ||
130 | root_devname = kmalloc(len, GFP_KERNEL); | ||
131 | if (root_devname == NULL) | ||
132 | return ERR_PTR(-ENOMEM); | ||
133 | /* Does hostname needs to be enclosed in brackets? */ | ||
134 | if (strchr(hostname, ':')) | ||
135 | snprintf(root_devname, len, "[%s]:/", hostname); | ||
136 | else | ||
137 | snprintf(root_devname, len, "%s:/", hostname); | ||
138 | root_mnt = vfs_kern_mount(fs_type, flags, root_devname, data); | ||
139 | kfree(root_devname); | ||
140 | return root_mnt; | ||
141 | } | ||
142 | |||
143 | struct nfs_referral_count { | ||
144 | struct list_head list; | ||
145 | const struct task_struct *task; | ||
146 | unsigned int referral_count; | ||
147 | }; | ||
148 | |||
149 | static LIST_HEAD(nfs_referral_count_list); | ||
150 | static DEFINE_SPINLOCK(nfs_referral_count_list_lock); | ||
151 | |||
152 | static struct nfs_referral_count *nfs_find_referral_count(void) | ||
153 | { | ||
154 | struct nfs_referral_count *p; | ||
155 | |||
156 | list_for_each_entry(p, &nfs_referral_count_list, list) { | ||
157 | if (p->task == current) | ||
158 | return p; | ||
159 | } | ||
160 | return NULL; | ||
161 | } | ||
162 | |||
163 | #define NFS_MAX_NESTED_REFERRALS 2 | ||
164 | |||
165 | static int nfs_referral_loop_protect(void) | ||
166 | { | ||
167 | struct nfs_referral_count *p, *new; | ||
168 | int ret = -ENOMEM; | ||
169 | |||
170 | new = kmalloc(sizeof(*new), GFP_KERNEL); | ||
171 | if (!new) | ||
172 | goto out; | ||
173 | new->task = current; | ||
174 | new->referral_count = 1; | ||
175 | |||
176 | ret = 0; | ||
177 | spin_lock(&nfs_referral_count_list_lock); | ||
178 | p = nfs_find_referral_count(); | ||
179 | if (p != NULL) { | ||
180 | if (p->referral_count >= NFS_MAX_NESTED_REFERRALS) | ||
181 | ret = -ELOOP; | ||
182 | else | ||
183 | p->referral_count++; | ||
184 | } else { | ||
185 | list_add(&new->list, &nfs_referral_count_list); | ||
186 | new = NULL; | ||
187 | } | ||
188 | spin_unlock(&nfs_referral_count_list_lock); | ||
189 | kfree(new); | ||
190 | out: | ||
191 | return ret; | ||
192 | } | ||
193 | |||
194 | static void nfs_referral_loop_unprotect(void) | ||
195 | { | ||
196 | struct nfs_referral_count *p; | ||
197 | |||
198 | spin_lock(&nfs_referral_count_list_lock); | ||
199 | p = nfs_find_referral_count(); | ||
200 | p->referral_count--; | ||
201 | if (p->referral_count == 0) | ||
202 | list_del(&p->list); | ||
203 | else | ||
204 | p = NULL; | ||
205 | spin_unlock(&nfs_referral_count_list_lock); | ||
206 | kfree(p); | ||
207 | } | ||
208 | |||
209 | static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt, | ||
210 | const char *export_path) | ||
211 | { | ||
212 | struct dentry *dentry; | ||
213 | int err; | ||
214 | |||
215 | if (IS_ERR(root_mnt)) | ||
216 | return ERR_CAST(root_mnt); | ||
217 | |||
218 | err = nfs_referral_loop_protect(); | ||
219 | if (err) { | ||
220 | mntput(root_mnt); | ||
221 | return ERR_PTR(err); | ||
222 | } | ||
223 | |||
224 | dentry = mount_subtree(root_mnt, export_path); | ||
225 | nfs_referral_loop_unprotect(); | ||
226 | |||
227 | return dentry; | ||
228 | } | ||
229 | |||
230 | struct dentry *nfs4_try_mount(int flags, const char *dev_name, | ||
231 | struct nfs_mount_info *mount_info) | ||
232 | { | ||
233 | char *export_path; | ||
234 | struct vfsmount *root_mnt; | ||
235 | struct dentry *res; | ||
236 | struct nfs_parsed_mount_data *data = mount_info->parsed; | ||
237 | |||
238 | dfprintk(MOUNT, "--> nfs4_try_mount()\n"); | ||
239 | |||
240 | mount_info->fill_super = nfs4_fill_super; | ||
241 | |||
242 | export_path = data->nfs_server.export_path; | ||
243 | data->nfs_server.export_path = "/"; | ||
244 | root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, mount_info, | ||
245 | data->nfs_server.hostname); | ||
246 | data->nfs_server.export_path = export_path; | ||
247 | |||
248 | res = nfs_follow_remote_path(root_mnt, export_path); | ||
249 | |||
250 | dfprintk(MOUNT, "<-- nfs4_try_mount() = %ld%s\n", | ||
251 | IS_ERR(res) ? PTR_ERR(res) : 0, | ||
252 | IS_ERR(res) ? " [error]" : ""); | ||
253 | return res; | ||
254 | } | ||
255 | |||
256 | /* | ||
257 | * Clone an NFS4 server record on xdev traversal (FSID-change) | ||
258 | */ | ||
259 | static struct dentry * | ||
260 | nfs4_xdev_mount(struct file_system_type *fs_type, int flags, | ||
261 | const char *dev_name, void *raw_data) | ||
262 | { | ||
263 | struct nfs_mount_info mount_info = { | ||
264 | .fill_super = nfs_clone_super, | ||
265 | .set_security = nfs_clone_sb_security, | ||
266 | .cloned = raw_data, | ||
267 | }; | ||
268 | return nfs_xdev_mount_common(&nfs4_fs_type, flags, dev_name, &mount_info); | ||
269 | } | ||
270 | |||
271 | static struct dentry * | ||
272 | nfs4_remote_referral_mount(struct file_system_type *fs_type, int flags, | ||
273 | const char *dev_name, void *raw_data) | ||
274 | { | ||
275 | struct nfs_mount_info mount_info = { | ||
276 | .fill_super = nfs4_fill_super, | ||
277 | .set_security = nfs_clone_sb_security, | ||
278 | .cloned = raw_data, | ||
279 | }; | ||
280 | struct nfs_server *server; | ||
281 | struct dentry *mntroot = ERR_PTR(-ENOMEM); | ||
282 | |||
283 | dprintk("--> nfs4_referral_get_sb()\n"); | ||
284 | |||
285 | mount_info.mntfh = nfs_alloc_fhandle(); | ||
286 | if (mount_info.cloned == NULL || mount_info.mntfh == NULL) | ||
287 | goto out; | ||
288 | |||
289 | /* create a new volume representation */ | ||
290 | server = nfs4_create_referral_server(mount_info.cloned, mount_info.mntfh); | ||
291 | if (IS_ERR(server)) { | ||
292 | mntroot = ERR_CAST(server); | ||
293 | goto out; | ||
294 | } | ||
295 | |||
296 | mntroot = nfs_fs_mount_common(&nfs4_fs_type, server, flags, dev_name, &mount_info); | ||
297 | out: | ||
298 | nfs_free_fhandle(mount_info.mntfh); | ||
299 | return mntroot; | ||
300 | } | ||
301 | |||
302 | /* | ||
303 | * Create an NFS4 server record on referral traversal | ||
304 | */ | ||
305 | static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type, | ||
306 | int flags, const char *dev_name, void *raw_data) | ||
307 | { | ||
308 | struct nfs_clone_mount *data = raw_data; | ||
309 | char *export_path; | ||
310 | struct vfsmount *root_mnt; | ||
311 | struct dentry *res; | ||
312 | |||
313 | dprintk("--> nfs4_referral_mount()\n"); | ||
314 | |||
315 | export_path = data->mnt_path; | ||
316 | data->mnt_path = "/"; | ||
317 | |||
318 | root_mnt = nfs_do_root_mount(&nfs4_remote_referral_fs_type, | ||
319 | flags, data, data->hostname); | ||
320 | data->mnt_path = export_path; | ||
321 | |||
322 | res = nfs_follow_remote_path(root_mnt, export_path); | ||
323 | dprintk("<-- nfs4_referral_mount() = %ld%s\n", | ||
324 | IS_ERR(res) ? PTR_ERR(res) : 0, | ||
325 | IS_ERR(res) ? " [error]" : ""); | ||
326 | return res; | ||
327 | } | ||
328 | |||
329 | |||
330 | int __init init_nfs_v4(void) | ||
331 | { | ||
332 | int err; | ||
333 | |||
334 | err = nfs_idmap_init(); | ||
335 | if (err) | ||
336 | goto out; | ||
337 | |||
338 | err = nfs4_register_sysctl(); | ||
339 | if (err) | ||
340 | goto out1; | ||
341 | |||
342 | err = register_filesystem(&nfs4_fs_type); | ||
343 | if (err < 0) | ||
344 | goto out2; | ||
345 | |||
346 | return 0; | ||
347 | out2: | ||
348 | nfs4_unregister_sysctl(); | ||
349 | out1: | ||
350 | nfs_idmap_quit(); | ||
351 | out: | ||
352 | return err; | ||
353 | } | ||
354 | |||
355 | void exit_nfs_v4(void) | ||
356 | { | ||
357 | unregister_filesystem(&nfs4_fs_type); | ||
358 | nfs4_unregister_sysctl(); | ||
359 | nfs_idmap_quit(); | ||
360 | } | ||
diff --git a/fs/nfs/nfs4sysctl.c b/fs/nfs/nfs4sysctl.c new file mode 100644 index 000000000000..5729bc8aa75d --- /dev/null +++ b/fs/nfs/nfs4sysctl.c | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | * linux/fs/nfs/nfs4sysctl.c | ||
3 | * | ||
4 | * Sysctl interface to NFS v4 parameters | ||
5 | * | ||
6 | * Copyright (c) 2006 Trond Myklebust <Trond.Myklebust@netapp.com> | ||
7 | */ | ||
8 | #include <linux/sysctl.h> | ||
9 | #include <linux/nfs_idmap.h> | ||
10 | #include <linux/nfs_fs.h> | ||
11 | |||
12 | #include "callback.h" | ||
13 | |||
14 | static const int nfs_set_port_min = 0; | ||
15 | static const int nfs_set_port_max = 65535; | ||
16 | static struct ctl_table_header *nfs4_callback_sysctl_table; | ||
17 | |||
18 | static ctl_table nfs4_cb_sysctls[] = { | ||
19 | { | ||
20 | .procname = "nfs_callback_tcpport", | ||
21 | .data = &nfs_callback_set_tcpport, | ||
22 | .maxlen = sizeof(int), | ||
23 | .mode = 0644, | ||
24 | .proc_handler = proc_dointvec_minmax, | ||
25 | .extra1 = (int *)&nfs_set_port_min, | ||
26 | .extra2 = (int *)&nfs_set_port_max, | ||
27 | }, | ||
28 | { | ||
29 | .procname = "idmap_cache_timeout", | ||
30 | .data = &nfs_idmap_cache_timeout, | ||
31 | .maxlen = sizeof(int), | ||
32 | .mode = 0644, | ||
33 | .proc_handler = proc_dointvec_jiffies, | ||
34 | }, | ||
35 | { } | ||
36 | }; | ||
37 | |||
38 | static ctl_table nfs4_cb_sysctl_dir[] = { | ||
39 | { | ||
40 | .procname = "nfs", | ||
41 | .mode = 0555, | ||
42 | .child = nfs4_cb_sysctls, | ||
43 | }, | ||
44 | { } | ||
45 | }; | ||
46 | |||
47 | static ctl_table nfs4_cb_sysctl_root[] = { | ||
48 | { | ||
49 | .procname = "fs", | ||
50 | .mode = 0555, | ||
51 | .child = nfs4_cb_sysctl_dir, | ||
52 | }, | ||
53 | { } | ||
54 | }; | ||
55 | |||
56 | int nfs4_register_sysctl(void) | ||
57 | { | ||
58 | nfs4_callback_sysctl_table = register_sysctl_table(nfs4_cb_sysctl_root); | ||
59 | if (nfs4_callback_sysctl_table == NULL) | ||
60 | return -ENOMEM; | ||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | void nfs4_unregister_sysctl(void) | ||
65 | { | ||
66 | unregister_sysctl_table(nfs4_callback_sysctl_table); | ||
67 | nfs4_callback_sysctl_table = NULL; | ||
68 | } | ||
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 18fae29b0301..6cbd602e26d5 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -1236,7 +1236,7 @@ static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct | |||
1236 | 1236 | ||
1237 | static inline int nfs4_lock_type(struct file_lock *fl, int block) | 1237 | static inline int nfs4_lock_type(struct file_lock *fl, int block) |
1238 | { | 1238 | { |
1239 | if ((fl->fl_type & (F_RDLCK|F_WRLCK|F_UNLCK)) == F_RDLCK) | 1239 | if (fl->fl_type == F_RDLCK) |
1240 | return block ? NFS4_READW_LT : NFS4_READ_LT; | 1240 | return block ? NFS4_READW_LT : NFS4_READ_LT; |
1241 | return block ? NFS4_WRITEW_LT : NFS4_WRITE_LT; | 1241 | return block ? NFS4_WRITEW_LT : NFS4_WRITE_LT; |
1242 | } | 1242 | } |
@@ -3078,7 +3078,7 @@ out_overflow: | |||
3078 | return -EIO; | 3078 | return -EIO; |
3079 | } | 3079 | } |
3080 | 3080 | ||
3081 | static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, __be32 **savep) | 3081 | static int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, unsigned int *savep) |
3082 | { | 3082 | { |
3083 | __be32 *p; | 3083 | __be32 *p; |
3084 | 3084 | ||
@@ -3086,7 +3086,7 @@ static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, | |||
3086 | if (unlikely(!p)) | 3086 | if (unlikely(!p)) |
3087 | goto out_overflow; | 3087 | goto out_overflow; |
3088 | *attrlen = be32_to_cpup(p); | 3088 | *attrlen = be32_to_cpup(p); |
3089 | *savep = xdr->p; | 3089 | *savep = xdr_stream_pos(xdr); |
3090 | return 0; | 3090 | return 0; |
3091 | out_overflow: | 3091 | out_overflow: |
3092 | print_overflow_msg(__func__, xdr); | 3092 | print_overflow_msg(__func__, xdr); |
@@ -4068,10 +4068,10 @@ static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, str | |||
4068 | return status; | 4068 | return status; |
4069 | } | 4069 | } |
4070 | 4070 | ||
4071 | static int verify_attr_len(struct xdr_stream *xdr, __be32 *savep, uint32_t attrlen) | 4071 | static int verify_attr_len(struct xdr_stream *xdr, unsigned int savep, uint32_t attrlen) |
4072 | { | 4072 | { |
4073 | unsigned int attrwords = XDR_QUADLEN(attrlen); | 4073 | unsigned int attrwords = XDR_QUADLEN(attrlen); |
4074 | unsigned int nwords = xdr->p - savep; | 4074 | unsigned int nwords = (xdr_stream_pos(xdr) - savep) >> 2; |
4075 | 4075 | ||
4076 | if (unlikely(attrwords != nwords)) { | 4076 | if (unlikely(attrwords != nwords)) { |
4077 | dprintk("%s: server returned incorrect attribute length: " | 4077 | dprintk("%s: server returned incorrect attribute length: " |
@@ -4158,13 +4158,18 @@ static int decode_verifier(struct xdr_stream *xdr, void *verifier) | |||
4158 | return decode_opaque_fixed(xdr, verifier, NFS4_VERIFIER_SIZE); | 4158 | return decode_opaque_fixed(xdr, verifier, NFS4_VERIFIER_SIZE); |
4159 | } | 4159 | } |
4160 | 4160 | ||
4161 | static int decode_write_verifier(struct xdr_stream *xdr, struct nfs_write_verifier *verifier) | ||
4162 | { | ||
4163 | return decode_opaque_fixed(xdr, verifier->data, NFS4_VERIFIER_SIZE); | ||
4164 | } | ||
4165 | |||
4161 | static int decode_commit(struct xdr_stream *xdr, struct nfs_commitres *res) | 4166 | static int decode_commit(struct xdr_stream *xdr, struct nfs_commitres *res) |
4162 | { | 4167 | { |
4163 | int status; | 4168 | int status; |
4164 | 4169 | ||
4165 | status = decode_op_hdr(xdr, OP_COMMIT); | 4170 | status = decode_op_hdr(xdr, OP_COMMIT); |
4166 | if (!status) | 4171 | if (!status) |
4167 | status = decode_verifier(xdr, res->verf->verifier); | 4172 | status = decode_write_verifier(xdr, &res->verf->verifier); |
4168 | return status; | 4173 | return status; |
4169 | } | 4174 | } |
4170 | 4175 | ||
@@ -4193,7 +4198,7 @@ out_overflow: | |||
4193 | 4198 | ||
4194 | static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res) | 4199 | static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res) |
4195 | { | 4200 | { |
4196 | __be32 *savep; | 4201 | unsigned int savep; |
4197 | uint32_t attrlen, bitmap[3] = {0}; | 4202 | uint32_t attrlen, bitmap[3] = {0}; |
4198 | int status; | 4203 | int status; |
4199 | 4204 | ||
@@ -4222,7 +4227,7 @@ xdr_error: | |||
4222 | 4227 | ||
4223 | static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat) | 4228 | static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat) |
4224 | { | 4229 | { |
4225 | __be32 *savep; | 4230 | unsigned int savep; |
4226 | uint32_t attrlen, bitmap[3] = {0}; | 4231 | uint32_t attrlen, bitmap[3] = {0}; |
4227 | int status; | 4232 | int status; |
4228 | 4233 | ||
@@ -4254,7 +4259,7 @@ xdr_error: | |||
4254 | 4259 | ||
4255 | static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf) | 4260 | static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf) |
4256 | { | 4261 | { |
4257 | __be32 *savep; | 4262 | unsigned int savep; |
4258 | uint32_t attrlen, bitmap[3] = {0}; | 4263 | uint32_t attrlen, bitmap[3] = {0}; |
4259 | int status; | 4264 | int status; |
4260 | 4265 | ||
@@ -4299,7 +4304,8 @@ out_overflow: | |||
4299 | static int decode_first_threshold_item4(struct xdr_stream *xdr, | 4304 | static int decode_first_threshold_item4(struct xdr_stream *xdr, |
4300 | struct nfs4_threshold *res) | 4305 | struct nfs4_threshold *res) |
4301 | { | 4306 | { |
4302 | __be32 *p, *savep; | 4307 | __be32 *p; |
4308 | unsigned int savep; | ||
4303 | uint32_t bitmap[3] = {0,}, attrlen; | 4309 | uint32_t bitmap[3] = {0,}, attrlen; |
4304 | int status; | 4310 | int status; |
4305 | 4311 | ||
@@ -4503,7 +4509,7 @@ static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fat | |||
4503 | struct nfs_fh *fh, struct nfs4_fs_locations *fs_loc, | 4509 | struct nfs_fh *fh, struct nfs4_fs_locations *fs_loc, |
4504 | const struct nfs_server *server) | 4510 | const struct nfs_server *server) |
4505 | { | 4511 | { |
4506 | __be32 *savep; | 4512 | unsigned int savep; |
4507 | uint32_t attrlen, | 4513 | uint32_t attrlen, |
4508 | bitmap[3] = {0}; | 4514 | bitmap[3] = {0}; |
4509 | int status; | 4515 | int status; |
@@ -4615,7 +4621,7 @@ static int decode_attr_layout_blksize(struct xdr_stream *xdr, uint32_t *bitmap, | |||
4615 | 4621 | ||
4616 | static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo) | 4622 | static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo) |
4617 | { | 4623 | { |
4618 | __be32 *savep; | 4624 | unsigned int savep; |
4619 | uint32_t attrlen, bitmap[3]; | 4625 | uint32_t attrlen, bitmap[3]; |
4620 | int status; | 4626 | int status; |
4621 | 4627 | ||
@@ -4920,9 +4926,8 @@ static int decode_putrootfh(struct xdr_stream *xdr) | |||
4920 | 4926 | ||
4921 | static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res) | 4927 | static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res) |
4922 | { | 4928 | { |
4923 | struct kvec *iov = req->rq_rcv_buf.head; | ||
4924 | __be32 *p; | 4929 | __be32 *p; |
4925 | uint32_t count, eof, recvd, hdrlen; | 4930 | uint32_t count, eof, recvd; |
4926 | int status; | 4931 | int status; |
4927 | 4932 | ||
4928 | status = decode_op_hdr(xdr, OP_READ); | 4933 | status = decode_op_hdr(xdr, OP_READ); |
@@ -4933,15 +4938,13 @@ static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_ | |||
4933 | goto out_overflow; | 4938 | goto out_overflow; |
4934 | eof = be32_to_cpup(p++); | 4939 | eof = be32_to_cpup(p++); |
4935 | count = be32_to_cpup(p); | 4940 | count = be32_to_cpup(p); |
4936 | hdrlen = (u8 *) xdr->p - (u8 *) iov->iov_base; | 4941 | recvd = xdr_read_pages(xdr, count); |
4937 | recvd = req->rq_rcv_buf.len - hdrlen; | ||
4938 | if (count > recvd) { | 4942 | if (count > recvd) { |
4939 | dprintk("NFS: server cheating in read reply: " | 4943 | dprintk("NFS: server cheating in read reply: " |
4940 | "count %u > recvd %u\n", count, recvd); | 4944 | "count %u > recvd %u\n", count, recvd); |
4941 | count = recvd; | 4945 | count = recvd; |
4942 | eof = 0; | 4946 | eof = 0; |
4943 | } | 4947 | } |
4944 | xdr_read_pages(xdr, count); | ||
4945 | res->eof = eof; | 4948 | res->eof = eof; |
4946 | res->count = count; | 4949 | res->count = count; |
4947 | return 0; | 4950 | return 0; |
@@ -4952,10 +4955,6 @@ out_overflow: | |||
4952 | 4955 | ||
4953 | static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir) | 4956 | static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir) |
4954 | { | 4957 | { |
4955 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; | ||
4956 | struct kvec *iov = rcvbuf->head; | ||
4957 | size_t hdrlen; | ||
4958 | u32 recvd, pglen = rcvbuf->page_len; | ||
4959 | int status; | 4958 | int status; |
4960 | __be32 verf[2]; | 4959 | __be32 verf[2]; |
4961 | 4960 | ||
@@ -4967,22 +4966,12 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
4967 | memcpy(verf, readdir->verifier.data, sizeof(verf)); | 4966 | memcpy(verf, readdir->verifier.data, sizeof(verf)); |
4968 | dprintk("%s: verifier = %08x:%08x\n", | 4967 | dprintk("%s: verifier = %08x:%08x\n", |
4969 | __func__, verf[0], verf[1]); | 4968 | __func__, verf[0], verf[1]); |
4970 | 4969 | return xdr_read_pages(xdr, xdr->buf->page_len); | |
4971 | hdrlen = (char *) xdr->p - (char *) iov->iov_base; | ||
4972 | recvd = rcvbuf->len - hdrlen; | ||
4973 | if (pglen > recvd) | ||
4974 | pglen = recvd; | ||
4975 | xdr_read_pages(xdr, pglen); | ||
4976 | |||
4977 | |||
4978 | return pglen; | ||
4979 | } | 4970 | } |
4980 | 4971 | ||
4981 | static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) | 4972 | static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) |
4982 | { | 4973 | { |
4983 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; | 4974 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; |
4984 | struct kvec *iov = rcvbuf->head; | ||
4985 | size_t hdrlen; | ||
4986 | u32 len, recvd; | 4975 | u32 len, recvd; |
4987 | __be32 *p; | 4976 | __be32 *p; |
4988 | int status; | 4977 | int status; |
@@ -5000,14 +4989,12 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) | |||
5000 | dprintk("nfs: server returned giant symlink!\n"); | 4989 | dprintk("nfs: server returned giant symlink!\n"); |
5001 | return -ENAMETOOLONG; | 4990 | return -ENAMETOOLONG; |
5002 | } | 4991 | } |
5003 | hdrlen = (char *) xdr->p - (char *) iov->iov_base; | 4992 | recvd = xdr_read_pages(xdr, len); |
5004 | recvd = req->rq_rcv_buf.len - hdrlen; | ||
5005 | if (recvd < len) { | 4993 | if (recvd < len) { |
5006 | dprintk("NFS: server cheating in readlink reply: " | 4994 | dprintk("NFS: server cheating in readlink reply: " |
5007 | "count %u > recvd %u\n", len, recvd); | 4995 | "count %u > recvd %u\n", len, recvd); |
5008 | return -EIO; | 4996 | return -EIO; |
5009 | } | 4997 | } |
5010 | xdr_read_pages(xdr, len); | ||
5011 | /* | 4998 | /* |
5012 | * The XDR encode routine has set things up so that | 4999 | * The XDR encode routine has set things up so that |
5013 | * the link text will be copied directly into the | 5000 | * the link text will be copied directly into the |
@@ -5063,10 +5050,10 @@ decode_restorefh(struct xdr_stream *xdr) | |||
5063 | static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, | 5050 | static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, |
5064 | struct nfs_getaclres *res) | 5051 | struct nfs_getaclres *res) |
5065 | { | 5052 | { |
5066 | __be32 *savep, *bm_p; | 5053 | unsigned int savep; |
5054 | __be32 *bm_p; | ||
5067 | uint32_t attrlen, | 5055 | uint32_t attrlen, |
5068 | bitmap[3] = {0}; | 5056 | bitmap[3] = {0}; |
5069 | struct kvec *iov = req->rq_rcv_buf.head; | ||
5070 | int status; | 5057 | int status; |
5071 | size_t page_len = xdr->buf->page_len; | 5058 | size_t page_len = xdr->buf->page_len; |
5072 | 5059 | ||
@@ -5089,7 +5076,6 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, | |||
5089 | if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U))) | 5076 | if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U))) |
5090 | return -EIO; | 5077 | return -EIO; |
5091 | if (likely(bitmap[0] & FATTR4_WORD0_ACL)) { | 5078 | if (likely(bitmap[0] & FATTR4_WORD0_ACL)) { |
5092 | size_t hdrlen; | ||
5093 | 5079 | ||
5094 | /* The bitmap (xdr len + bitmaps) and the attr xdr len words | 5080 | /* The bitmap (xdr len + bitmaps) and the attr xdr len words |
5095 | * are stored with the acl data to handle the problem of | 5081 | * are stored with the acl data to handle the problem of |
@@ -5098,7 +5084,6 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, | |||
5098 | 5084 | ||
5099 | /* We ignore &savep and don't do consistency checks on | 5085 | /* We ignore &savep and don't do consistency checks on |
5100 | * the attr length. Let userspace figure it out.... */ | 5086 | * the attr length. Let userspace figure it out.... */ |
5101 | hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base; | ||
5102 | attrlen += res->acl_data_offset; | 5087 | attrlen += res->acl_data_offset; |
5103 | if (attrlen > page_len) { | 5088 | if (attrlen > page_len) { |
5104 | if (res->acl_flags & NFS4_ACL_LEN_REQUEST) { | 5089 | if (res->acl_flags & NFS4_ACL_LEN_REQUEST) { |
@@ -5212,13 +5197,12 @@ static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res) | |||
5212 | if (status) | 5197 | if (status) |
5213 | return status; | 5198 | return status; |
5214 | 5199 | ||
5215 | p = xdr_inline_decode(xdr, 16); | 5200 | p = xdr_inline_decode(xdr, 8); |
5216 | if (unlikely(!p)) | 5201 | if (unlikely(!p)) |
5217 | goto out_overflow; | 5202 | goto out_overflow; |
5218 | res->count = be32_to_cpup(p++); | 5203 | res->count = be32_to_cpup(p++); |
5219 | res->verf->committed = be32_to_cpup(p++); | 5204 | res->verf->committed = be32_to_cpup(p++); |
5220 | memcpy(res->verf->verifier, p, NFS4_VERIFIER_SIZE); | 5205 | return decode_write_verifier(xdr, &res->verf->verifier); |
5221 | return 0; | ||
5222 | out_overflow: | 5206 | out_overflow: |
5223 | print_overflow_msg(__func__, xdr); | 5207 | print_overflow_msg(__func__, xdr); |
5224 | return -EIO; | 5208 | return -EIO; |
@@ -5599,7 +5583,7 @@ static int decode_getdevicelist(struct xdr_stream *xdr, | |||
5599 | { | 5583 | { |
5600 | __be32 *p; | 5584 | __be32 *p; |
5601 | int status, i; | 5585 | int status, i; |
5602 | struct nfs_writeverf verftemp; | 5586 | nfs4_verifier verftemp; |
5603 | 5587 | ||
5604 | status = decode_op_hdr(xdr, OP_GETDEVICELIST); | 5588 | status = decode_op_hdr(xdr, OP_GETDEVICELIST); |
5605 | if (status) | 5589 | if (status) |
@@ -5613,7 +5597,7 @@ static int decode_getdevicelist(struct xdr_stream *xdr, | |||
5613 | p += 2; | 5597 | p += 2; |
5614 | 5598 | ||
5615 | /* Read verifier */ | 5599 | /* Read verifier */ |
5616 | p = xdr_decode_opaque_fixed(p, verftemp.verifier, NFS4_VERIFIER_SIZE); | 5600 | p = xdr_decode_opaque_fixed(p, verftemp.data, NFS4_VERIFIER_SIZE); |
5617 | 5601 | ||
5618 | res->num_devs = be32_to_cpup(p); | 5602 | res->num_devs = be32_to_cpup(p); |
5619 | 5603 | ||
@@ -5707,9 +5691,7 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req, | |||
5707 | __be32 *p; | 5691 | __be32 *p; |
5708 | int status; | 5692 | int status; |
5709 | u32 layout_count; | 5693 | u32 layout_count; |
5710 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; | 5694 | u32 recvd; |
5711 | struct kvec *iov = rcvbuf->head; | ||
5712 | u32 hdrlen, recvd; | ||
5713 | 5695 | ||
5714 | status = decode_op_hdr(xdr, OP_LAYOUTGET); | 5696 | status = decode_op_hdr(xdr, OP_LAYOUTGET); |
5715 | if (status) | 5697 | if (status) |
@@ -5746,8 +5728,7 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req, | |||
5746 | res->type, | 5728 | res->type, |
5747 | res->layoutp->len); | 5729 | res->layoutp->len); |
5748 | 5730 | ||
5749 | hdrlen = (u8 *) xdr->p - (u8 *) iov->iov_base; | 5731 | recvd = xdr_read_pages(xdr, res->layoutp->len); |
5750 | recvd = req->rq_rcv_buf.len - hdrlen; | ||
5751 | if (res->layoutp->len > recvd) { | 5732 | if (res->layoutp->len > recvd) { |
5752 | dprintk("NFS: server cheating in layoutget reply: " | 5733 | dprintk("NFS: server cheating in layoutget reply: " |
5753 | "layout len %u > recvd %u\n", | 5734 | "layout len %u > recvd %u\n", |
@@ -5755,8 +5736,6 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req, | |||
5755 | return -EINVAL; | 5736 | return -EINVAL; |
5756 | } | 5737 | } |
5757 | 5738 | ||
5758 | xdr_read_pages(xdr, res->layoutp->len); | ||
5759 | |||
5760 | if (layout_count > 1) { | 5739 | if (layout_count > 1) { |
5761 | /* We only handle a length one array at the moment. Any | 5740 | /* We only handle a length one array at the moment. Any |
5762 | * further entries are just ignored. Note that this means | 5741 | * further entries are just ignored. Note that this means |
@@ -7103,6 +7082,7 @@ out: | |||
7103 | int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, | 7082 | int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, |
7104 | int plus) | 7083 | int plus) |
7105 | { | 7084 | { |
7085 | unsigned int savep; | ||
7106 | uint32_t bitmap[3] = {0}; | 7086 | uint32_t bitmap[3] = {0}; |
7107 | uint32_t len; | 7087 | uint32_t len; |
7108 | __be32 *p = xdr_inline_decode(xdr, 4); | 7088 | __be32 *p = xdr_inline_decode(xdr, 4); |
@@ -7141,7 +7121,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, | |||
7141 | if (decode_attr_bitmap(xdr, bitmap) < 0) | 7121 | if (decode_attr_bitmap(xdr, bitmap) < 0) |
7142 | goto out_overflow; | 7122 | goto out_overflow; |
7143 | 7123 | ||
7144 | if (decode_attr_length(xdr, &len, &p) < 0) | 7124 | if (decode_attr_length(xdr, &len, &savep) < 0) |
7145 | goto out_overflow; | 7125 | goto out_overflow; |
7146 | 7126 | ||
7147 | if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh, | 7127 | if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh, |
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index bbc49caa7a82..7fbd25afe418 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -651,7 +651,14 @@ out_err_free: | |||
651 | return NULL; | 651 | return NULL; |
652 | } | 652 | } |
653 | 653 | ||
654 | /* Initiates a LAYOUTRETURN(FILE) */ | 654 | /* |
655 | * Initiates a LAYOUTRETURN(FILE), and removes the pnfs_layout_hdr | ||
656 | * when the layout segment list is empty. | ||
657 | * | ||
658 | * Note that a pnfs_layout_hdr can exist with an empty layout segment | ||
659 | * list when LAYOUTGET has failed, or when LAYOUTGET succeeded, but the | ||
660 | * deviceid is marked invalid. | ||
661 | */ | ||
655 | int | 662 | int |
656 | _pnfs_return_layout(struct inode *ino) | 663 | _pnfs_return_layout(struct inode *ino) |
657 | { | 664 | { |
@@ -660,22 +667,31 @@ _pnfs_return_layout(struct inode *ino) | |||
660 | LIST_HEAD(tmp_list); | 667 | LIST_HEAD(tmp_list); |
661 | struct nfs4_layoutreturn *lrp; | 668 | struct nfs4_layoutreturn *lrp; |
662 | nfs4_stateid stateid; | 669 | nfs4_stateid stateid; |
663 | int status = 0; | 670 | int status = 0, empty; |
664 | 671 | ||
665 | dprintk("--> %s\n", __func__); | 672 | dprintk("NFS: %s for inode %lu\n", __func__, ino->i_ino); |
666 | 673 | ||
667 | spin_lock(&ino->i_lock); | 674 | spin_lock(&ino->i_lock); |
668 | lo = nfsi->layout; | 675 | lo = nfsi->layout; |
669 | if (!lo) { | 676 | if (!lo || pnfs_test_layout_returned(lo)) { |
670 | spin_unlock(&ino->i_lock); | 677 | spin_unlock(&ino->i_lock); |
671 | dprintk("%s: no layout to return\n", __func__); | 678 | dprintk("NFS: %s no layout to return\n", __func__); |
672 | return status; | 679 | goto out; |
673 | } | 680 | } |
674 | stateid = nfsi->layout->plh_stateid; | 681 | stateid = nfsi->layout->plh_stateid; |
675 | /* Reference matched in nfs4_layoutreturn_release */ | 682 | /* Reference matched in nfs4_layoutreturn_release */ |
676 | get_layout_hdr(lo); | 683 | get_layout_hdr(lo); |
684 | empty = list_empty(&lo->plh_segs); | ||
677 | mark_matching_lsegs_invalid(lo, &tmp_list, NULL); | 685 | mark_matching_lsegs_invalid(lo, &tmp_list, NULL); |
686 | /* Don't send a LAYOUTRETURN if list was initially empty */ | ||
687 | if (empty) { | ||
688 | spin_unlock(&ino->i_lock); | ||
689 | put_layout_hdr(lo); | ||
690 | dprintk("NFS: %s no layout segments to return\n", __func__); | ||
691 | goto out; | ||
692 | } | ||
678 | lo->plh_block_lgets++; | 693 | lo->plh_block_lgets++; |
694 | pnfs_mark_layout_returned(lo); | ||
679 | spin_unlock(&ino->i_lock); | 695 | spin_unlock(&ino->i_lock); |
680 | pnfs_free_lseg_list(&tmp_list); | 696 | pnfs_free_lseg_list(&tmp_list); |
681 | 697 | ||
@@ -686,6 +702,7 @@ _pnfs_return_layout(struct inode *ino) | |||
686 | status = -ENOMEM; | 702 | status = -ENOMEM; |
687 | set_bit(NFS_LAYOUT_RW_FAILED, &lo->plh_flags); | 703 | set_bit(NFS_LAYOUT_RW_FAILED, &lo->plh_flags); |
688 | set_bit(NFS_LAYOUT_RO_FAILED, &lo->plh_flags); | 704 | set_bit(NFS_LAYOUT_RO_FAILED, &lo->plh_flags); |
705 | pnfs_clear_layout_returned(lo); | ||
689 | put_layout_hdr(lo); | 706 | put_layout_hdr(lo); |
690 | goto out; | 707 | goto out; |
691 | } | 708 | } |
@@ -1075,6 +1092,10 @@ pnfs_update_layout(struct inode *ino, | |||
1075 | get_layout_hdr(lo); | 1092 | get_layout_hdr(lo); |
1076 | if (list_empty(&lo->plh_segs)) | 1093 | if (list_empty(&lo->plh_segs)) |
1077 | first = true; | 1094 | first = true; |
1095 | |||
1096 | /* Enable LAYOUTRETURNs */ | ||
1097 | pnfs_clear_layout_returned(lo); | ||
1098 | |||
1078 | spin_unlock(&ino->i_lock); | 1099 | spin_unlock(&ino->i_lock); |
1079 | if (first) { | 1100 | if (first) { |
1080 | /* The lo must be on the clp list if there is any | 1101 | /* The lo must be on the clp list if there is any |
@@ -1209,7 +1230,7 @@ pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_page * | |||
1209 | } | 1230 | } |
1210 | EXPORT_SYMBOL_GPL(pnfs_generic_pg_init_write); | 1231 | EXPORT_SYMBOL_GPL(pnfs_generic_pg_init_write); |
1211 | 1232 | ||
1212 | bool | 1233 | void |
1213 | pnfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, struct inode *inode, | 1234 | pnfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, struct inode *inode, |
1214 | const struct nfs_pgio_completion_ops *compl_ops) | 1235 | const struct nfs_pgio_completion_ops *compl_ops) |
1215 | { | 1236 | { |
@@ -1217,13 +1238,12 @@ pnfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, struct inode *inode, | |||
1217 | struct pnfs_layoutdriver_type *ld = server->pnfs_curr_ld; | 1238 | struct pnfs_layoutdriver_type *ld = server->pnfs_curr_ld; |
1218 | 1239 | ||
1219 | if (ld == NULL) | 1240 | if (ld == NULL) |
1220 | return false; | 1241 | nfs_pageio_init_read(pgio, inode, compl_ops); |
1221 | nfs_pageio_init(pgio, inode, ld->pg_read_ops, compl_ops, | 1242 | else |
1222 | server->rsize, 0); | 1243 | nfs_pageio_init(pgio, inode, ld->pg_read_ops, compl_ops, server->rsize, 0); |
1223 | return true; | ||
1224 | } | 1244 | } |
1225 | 1245 | ||
1226 | bool | 1246 | void |
1227 | pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *inode, | 1247 | pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *inode, |
1228 | int ioflags, | 1248 | int ioflags, |
1229 | const struct nfs_pgio_completion_ops *compl_ops) | 1249 | const struct nfs_pgio_completion_ops *compl_ops) |
@@ -1232,10 +1252,9 @@ pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *inode, | |||
1232 | struct pnfs_layoutdriver_type *ld = server->pnfs_curr_ld; | 1252 | struct pnfs_layoutdriver_type *ld = server->pnfs_curr_ld; |
1233 | 1253 | ||
1234 | if (ld == NULL) | 1254 | if (ld == NULL) |
1235 | return false; | 1255 | nfs_pageio_init_write(pgio, inode, ioflags, compl_ops); |
1236 | nfs_pageio_init(pgio, inode, ld->pg_write_ops, compl_ops, | 1256 | else |
1237 | server->wsize, ioflags); | 1257 | nfs_pageio_init(pgio, inode, ld->pg_write_ops, compl_ops, server->wsize, ioflags); |
1238 | return true; | ||
1239 | } | 1258 | } |
1240 | 1259 | ||
1241 | bool | 1260 | bool |
@@ -1272,7 +1291,7 @@ int pnfs_write_done_resend_to_mds(struct inode *inode, | |||
1272 | LIST_HEAD(failed); | 1291 | LIST_HEAD(failed); |
1273 | 1292 | ||
1274 | /* Resend all requests through the MDS */ | 1293 | /* Resend all requests through the MDS */ |
1275 | nfs_pageio_init_write_mds(&pgio, inode, FLUSH_STABLE, compl_ops); | 1294 | nfs_pageio_init_write(&pgio, inode, FLUSH_STABLE, compl_ops); |
1276 | while (!list_empty(head)) { | 1295 | while (!list_empty(head)) { |
1277 | struct nfs_page *req = nfs_list_entry(head->next); | 1296 | struct nfs_page *req = nfs_list_entry(head->next); |
1278 | 1297 | ||
@@ -1427,7 +1446,7 @@ int pnfs_read_done_resend_to_mds(struct inode *inode, | |||
1427 | LIST_HEAD(failed); | 1446 | LIST_HEAD(failed); |
1428 | 1447 | ||
1429 | /* Resend all requests through the MDS */ | 1448 | /* Resend all requests through the MDS */ |
1430 | nfs_pageio_init_read_mds(&pgio, inode, compl_ops); | 1449 | nfs_pageio_init_read(&pgio, inode, compl_ops); |
1431 | while (!list_empty(head)) { | 1450 | while (!list_empty(head)) { |
1432 | struct nfs_page *req = nfs_list_entry(head->next); | 1451 | struct nfs_page *req = nfs_list_entry(head->next); |
1433 | 1452 | ||
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 64f90d845f6a..2c6c80503ba4 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h | |||
@@ -64,6 +64,7 @@ enum { | |||
64 | NFS_LAYOUT_ROC, /* some lseg had roc bit set */ | 64 | NFS_LAYOUT_ROC, /* some lseg had roc bit set */ |
65 | NFS_LAYOUT_DESTROYED, /* no new use of layout allowed */ | 65 | NFS_LAYOUT_DESTROYED, /* no new use of layout allowed */ |
66 | NFS_LAYOUT_INVALID, /* layout is being destroyed */ | 66 | NFS_LAYOUT_INVALID, /* layout is being destroyed */ |
67 | NFS_LAYOUT_RETURNED, /* layout has already been returned */ | ||
67 | }; | 68 | }; |
68 | 69 | ||
69 | enum layoutdriver_policy_flags { | 70 | enum layoutdriver_policy_flags { |
@@ -178,9 +179,9 @@ extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp); | |||
178 | void get_layout_hdr(struct pnfs_layout_hdr *lo); | 179 | void get_layout_hdr(struct pnfs_layout_hdr *lo); |
179 | void put_lseg(struct pnfs_layout_segment *lseg); | 180 | void put_lseg(struct pnfs_layout_segment *lseg); |
180 | 181 | ||
181 | bool pnfs_pageio_init_read(struct nfs_pageio_descriptor *, struct inode *, | 182 | void pnfs_pageio_init_read(struct nfs_pageio_descriptor *, struct inode *, |
182 | const struct nfs_pgio_completion_ops *); | 183 | const struct nfs_pgio_completion_ops *); |
183 | bool pnfs_pageio_init_write(struct nfs_pageio_descriptor *, struct inode *, | 184 | void pnfs_pageio_init_write(struct nfs_pageio_descriptor *, struct inode *, |
184 | int, const struct nfs_pgio_completion_ops *); | 185 | int, const struct nfs_pgio_completion_ops *); |
185 | 186 | ||
186 | void set_pnfs_layoutdriver(struct nfs_server *, const struct nfs_fh *, u32); | 187 | void set_pnfs_layoutdriver(struct nfs_server *, const struct nfs_fh *, u32); |
@@ -255,6 +256,24 @@ struct nfs4_deviceid_node *nfs4_insert_deviceid_node(struct nfs4_deviceid_node * | |||
255 | bool nfs4_put_deviceid_node(struct nfs4_deviceid_node *); | 256 | bool nfs4_put_deviceid_node(struct nfs4_deviceid_node *); |
256 | void nfs4_deviceid_purge_client(const struct nfs_client *); | 257 | void nfs4_deviceid_purge_client(const struct nfs_client *); |
257 | 258 | ||
259 | static inline void | ||
260 | pnfs_mark_layout_returned(struct pnfs_layout_hdr *lo) | ||
261 | { | ||
262 | set_bit(NFS_LAYOUT_RETURNED, &lo->plh_flags); | ||
263 | } | ||
264 | |||
265 | static inline void | ||
266 | pnfs_clear_layout_returned(struct pnfs_layout_hdr *lo) | ||
267 | { | ||
268 | clear_bit(NFS_LAYOUT_RETURNED, &lo->plh_flags); | ||
269 | } | ||
270 | |||
271 | static inline bool | ||
272 | pnfs_test_layout_returned(struct pnfs_layout_hdr *lo) | ||
273 | { | ||
274 | return test_bit(NFS_LAYOUT_RETURNED, &lo->plh_flags); | ||
275 | } | ||
276 | |||
258 | static inline int lo_fail_bit(u32 iomode) | 277 | static inline int lo_fail_bit(u32 iomode) |
259 | { | 278 | { |
260 | return iomode == IOMODE_RW ? | 279 | return iomode == IOMODE_RW ? |
@@ -438,16 +457,16 @@ static inline void unset_pnfs_layoutdriver(struct nfs_server *s) | |||
438 | { | 457 | { |
439 | } | 458 | } |
440 | 459 | ||
441 | static inline bool pnfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, struct inode *inode, | 460 | static inline void pnfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, struct inode *inode, |
442 | const struct nfs_pgio_completion_ops *compl_ops) | 461 | const struct nfs_pgio_completion_ops *compl_ops) |
443 | { | 462 | { |
444 | return false; | 463 | nfs_pageio_init_read(pgio, inode, compl_ops); |
445 | } | 464 | } |
446 | 465 | ||
447 | static inline bool pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *inode, int ioflags, | 466 | static inline void pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *inode, int ioflags, |
448 | const struct nfs_pgio_completion_ops *compl_ops) | 467 | const struct nfs_pgio_completion_ops *compl_ops) |
449 | { | 468 | { |
450 | return false; | 469 | nfs_pageio_init_write(pgio, inode, ioflags, compl_ops); |
451 | } | 470 | } |
452 | 471 | ||
453 | static inline int | 472 | static inline int |
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index 4433806e116f..4d3356af3309 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c | |||
@@ -734,6 +734,38 @@ out_einval: | |||
734 | return -EINVAL; | 734 | return -EINVAL; |
735 | } | 735 | } |
736 | 736 | ||
737 | static int nfs_have_delegation(struct inode *inode, fmode_t flags) | ||
738 | { | ||
739 | return 0; | ||
740 | } | ||
741 | |||
742 | static int nfs_return_delegation(struct inode *inode) | ||
743 | { | ||
744 | nfs_wb_all(inode); | ||
745 | return 0; | ||
746 | } | ||
747 | |||
748 | static const struct inode_operations nfs_dir_inode_operations = { | ||
749 | .create = nfs_create, | ||
750 | .lookup = nfs_lookup, | ||
751 | .link = nfs_link, | ||
752 | .unlink = nfs_unlink, | ||
753 | .symlink = nfs_symlink, | ||
754 | .mkdir = nfs_mkdir, | ||
755 | .rmdir = nfs_rmdir, | ||
756 | .mknod = nfs_mknod, | ||
757 | .rename = nfs_rename, | ||
758 | .permission = nfs_permission, | ||
759 | .getattr = nfs_getattr, | ||
760 | .setattr = nfs_setattr, | ||
761 | }; | ||
762 | |||
763 | static const struct inode_operations nfs_file_inode_operations = { | ||
764 | .permission = nfs_permission, | ||
765 | .getattr = nfs_getattr, | ||
766 | .setattr = nfs_setattr, | ||
767 | }; | ||
768 | |||
737 | const struct nfs_rpc_ops nfs_v2_clientops = { | 769 | const struct nfs_rpc_ops nfs_v2_clientops = { |
738 | .version = 2, /* protocol version */ | 770 | .version = 2, /* protocol version */ |
739 | .dentry_ops = &nfs_dentry_operations, | 771 | .dentry_ops = &nfs_dentry_operations, |
@@ -767,9 +799,11 @@ const struct nfs_rpc_ops nfs_v2_clientops = { | |||
767 | .pathconf = nfs_proc_pathconf, | 799 | .pathconf = nfs_proc_pathconf, |
768 | .decode_dirent = nfs2_decode_dirent, | 800 | .decode_dirent = nfs2_decode_dirent, |
769 | .read_setup = nfs_proc_read_setup, | 801 | .read_setup = nfs_proc_read_setup, |
802 | .read_pageio_init = nfs_pageio_init_read, | ||
770 | .read_rpc_prepare = nfs_proc_read_rpc_prepare, | 803 | .read_rpc_prepare = nfs_proc_read_rpc_prepare, |
771 | .read_done = nfs_read_done, | 804 | .read_done = nfs_read_done, |
772 | .write_setup = nfs_proc_write_setup, | 805 | .write_setup = nfs_proc_write_setup, |
806 | .write_pageio_init = nfs_pageio_init_write, | ||
773 | .write_rpc_prepare = nfs_proc_write_rpc_prepare, | 807 | .write_rpc_prepare = nfs_proc_write_rpc_prepare, |
774 | .write_done = nfs_write_done, | 808 | .write_done = nfs_write_done, |
775 | .commit_setup = nfs_proc_commit_setup, | 809 | .commit_setup = nfs_proc_commit_setup, |
@@ -777,5 +811,9 @@ const struct nfs_rpc_ops nfs_v2_clientops = { | |||
777 | .lock = nfs_proc_lock, | 811 | .lock = nfs_proc_lock, |
778 | .lock_check_bounds = nfs_lock_check_bounds, | 812 | .lock_check_bounds = nfs_lock_check_bounds, |
779 | .close_context = nfs_close_context, | 813 | .close_context = nfs_close_context, |
814 | .have_delegation = nfs_have_delegation, | ||
815 | .return_delegation = nfs_return_delegation, | ||
816 | .alloc_client = nfs_alloc_client, | ||
780 | .init_client = nfs_init_client, | 817 | .init_client = nfs_init_client, |
818 | .free_client = nfs_free_client, | ||
781 | }; | 819 | }; |
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 86ced7836214..6267b873bbcb 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -20,8 +20,6 @@ | |||
20 | #include <linux/nfs_page.h> | 20 | #include <linux/nfs_page.h> |
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | 22 | ||
23 | #include "pnfs.h" | ||
24 | |||
25 | #include "nfs4_fs.h" | 23 | #include "nfs4_fs.h" |
26 | #include "internal.h" | 24 | #include "internal.h" |
27 | #include "iostat.h" | 25 | #include "iostat.h" |
@@ -108,7 +106,7 @@ int nfs_return_empty_page(struct page *page) | |||
108 | return 0; | 106 | return 0; |
109 | } | 107 | } |
110 | 108 | ||
111 | void nfs_pageio_init_read_mds(struct nfs_pageio_descriptor *pgio, | 109 | void nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, |
112 | struct inode *inode, | 110 | struct inode *inode, |
113 | const struct nfs_pgio_completion_ops *compl_ops) | 111 | const struct nfs_pgio_completion_ops *compl_ops) |
114 | { | 112 | { |
@@ -123,14 +121,6 @@ void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio) | |||
123 | } | 121 | } |
124 | EXPORT_SYMBOL_GPL(nfs_pageio_reset_read_mds); | 122 | EXPORT_SYMBOL_GPL(nfs_pageio_reset_read_mds); |
125 | 123 | ||
126 | void nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, | ||
127 | struct inode *inode, | ||
128 | const struct nfs_pgio_completion_ops *compl_ops) | ||
129 | { | ||
130 | if (!pnfs_pageio_init_read(pgio, inode, compl_ops)) | ||
131 | nfs_pageio_init_read_mds(pgio, inode, compl_ops); | ||
132 | } | ||
133 | |||
134 | int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, | 124 | int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, |
135 | struct page *page) | 125 | struct page *page) |
136 | { | 126 | { |
@@ -149,7 +139,7 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, | |||
149 | if (len < PAGE_CACHE_SIZE) | 139 | if (len < PAGE_CACHE_SIZE) |
150 | zero_user_segment(page, len, PAGE_CACHE_SIZE); | 140 | zero_user_segment(page, len, PAGE_CACHE_SIZE); |
151 | 141 | ||
152 | nfs_pageio_init_read(&pgio, inode, &nfs_async_read_completion_ops); | 142 | NFS_PROTO(inode)->read_pageio_init(&pgio, inode, &nfs_async_read_completion_ops); |
153 | nfs_pageio_add_request(&pgio, new); | 143 | nfs_pageio_add_request(&pgio, new); |
154 | nfs_pageio_complete(&pgio); | 144 | nfs_pageio_complete(&pgio); |
155 | NFS_I(inode)->read_io += pgio.pg_bytes_written; | 145 | NFS_I(inode)->read_io += pgio.pg_bytes_written; |
@@ -652,7 +642,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping, | |||
652 | if (ret == 0) | 642 | if (ret == 0) |
653 | goto read_complete; /* all pages were read */ | 643 | goto read_complete; /* all pages were read */ |
654 | 644 | ||
655 | nfs_pageio_init_read(&pgio, inode, &nfs_async_read_completion_ops); | 645 | NFS_PROTO(inode)->read_pageio_init(&pgio, inode, &nfs_async_read_completion_ops); |
656 | 646 | ||
657 | ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc); | 647 | ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc); |
658 | 648 | ||
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 8b2a2977b720..95866a8c21bb 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -278,29 +278,8 @@ static match_table_t nfs_vers_tokens = { | |||
278 | { Opt_vers_err, NULL } | 278 | { Opt_vers_err, NULL } |
279 | }; | 279 | }; |
280 | 280 | ||
281 | struct nfs_mount_info { | ||
282 | void (*fill_super)(struct super_block *, struct nfs_mount_info *); | ||
283 | int (*set_security)(struct super_block *, struct dentry *, struct nfs_mount_info *); | ||
284 | struct nfs_parsed_mount_data *parsed; | ||
285 | struct nfs_clone_mount *cloned; | ||
286 | struct nfs_fh *mntfh; | ||
287 | }; | ||
288 | |||
289 | static void nfs_umount_begin(struct super_block *); | ||
290 | static int nfs_statfs(struct dentry *, struct kstatfs *); | ||
291 | static int nfs_show_options(struct seq_file *, struct dentry *); | ||
292 | static int nfs_show_devname(struct seq_file *, struct dentry *); | ||
293 | static int nfs_show_path(struct seq_file *, struct dentry *); | ||
294 | static int nfs_show_stats(struct seq_file *, struct dentry *); | ||
295 | static struct dentry *nfs_fs_mount_common(struct file_system_type *, | ||
296 | struct nfs_server *, int, const char *, struct nfs_mount_info *); | ||
297 | static struct dentry *nfs_fs_mount(struct file_system_type *, | ||
298 | int, const char *, void *); | ||
299 | static struct dentry *nfs_xdev_mount(struct file_system_type *fs_type, | 281 | static struct dentry *nfs_xdev_mount(struct file_system_type *fs_type, |
300 | int flags, const char *dev_name, void *raw_data); | 282 | int flags, const char *dev_name, void *raw_data); |
301 | static void nfs_put_super(struct super_block *); | ||
302 | static void nfs_kill_super(struct super_block *); | ||
303 | static int nfs_remount(struct super_block *sb, int *flags, char *raw_data); | ||
304 | 283 | ||
305 | static struct file_system_type nfs_fs_type = { | 284 | static struct file_system_type nfs_fs_type = { |
306 | .owner = THIS_MODULE, | 285 | .owner = THIS_MODULE, |
@@ -337,72 +316,6 @@ static const struct super_operations nfs_sops = { | |||
337 | static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *); | 316 | static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *); |
338 | static int nfs4_validate_mount_data(void *options, | 317 | static int nfs4_validate_mount_data(void *options, |
339 | struct nfs_parsed_mount_data *args, const char *dev_name); | 318 | struct nfs_parsed_mount_data *args, const char *dev_name); |
340 | static struct dentry *nfs4_try_mount(int flags, const char *dev_name, | ||
341 | struct nfs_mount_info *mount_info); | ||
342 | static struct dentry *nfs4_remote_mount(struct file_system_type *fs_type, | ||
343 | int flags, const char *dev_name, void *raw_data); | ||
344 | static struct dentry *nfs4_xdev_mount(struct file_system_type *fs_type, | ||
345 | int flags, const char *dev_name, void *raw_data); | ||
346 | static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type, | ||
347 | int flags, const char *dev_name, void *raw_data); | ||
348 | static struct dentry *nfs4_remote_referral_mount(struct file_system_type *fs_type, | ||
349 | int flags, const char *dev_name, void *raw_data); | ||
350 | static void nfs4_kill_super(struct super_block *sb); | ||
351 | |||
352 | static struct file_system_type nfs4_fs_type = { | ||
353 | .owner = THIS_MODULE, | ||
354 | .name = "nfs4", | ||
355 | .mount = nfs_fs_mount, | ||
356 | .kill_sb = nfs4_kill_super, | ||
357 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
358 | }; | ||
359 | |||
360 | static struct file_system_type nfs4_remote_fs_type = { | ||
361 | .owner = THIS_MODULE, | ||
362 | .name = "nfs4", | ||
363 | .mount = nfs4_remote_mount, | ||
364 | .kill_sb = nfs4_kill_super, | ||
365 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
366 | }; | ||
367 | |||
368 | struct file_system_type nfs4_xdev_fs_type = { | ||
369 | .owner = THIS_MODULE, | ||
370 | .name = "nfs4", | ||
371 | .mount = nfs4_xdev_mount, | ||
372 | .kill_sb = nfs4_kill_super, | ||
373 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
374 | }; | ||
375 | |||
376 | static struct file_system_type nfs4_remote_referral_fs_type = { | ||
377 | .owner = THIS_MODULE, | ||
378 | .name = "nfs4", | ||
379 | .mount = nfs4_remote_referral_mount, | ||
380 | .kill_sb = nfs4_kill_super, | ||
381 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
382 | }; | ||
383 | |||
384 | struct file_system_type nfs4_referral_fs_type = { | ||
385 | .owner = THIS_MODULE, | ||
386 | .name = "nfs4", | ||
387 | .mount = nfs4_referral_mount, | ||
388 | .kill_sb = nfs4_kill_super, | ||
389 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
390 | }; | ||
391 | |||
392 | static const struct super_operations nfs4_sops = { | ||
393 | .alloc_inode = nfs_alloc_inode, | ||
394 | .destroy_inode = nfs_destroy_inode, | ||
395 | .write_inode = nfs_write_inode, | ||
396 | .put_super = nfs_put_super, | ||
397 | .statfs = nfs_statfs, | ||
398 | .evict_inode = nfs4_evict_inode, | ||
399 | .umount_begin = nfs_umount_begin, | ||
400 | .show_options = nfs_show_options, | ||
401 | .show_devname = nfs_show_devname, | ||
402 | .show_path = nfs_show_path, | ||
403 | .show_stats = nfs_show_stats, | ||
404 | .remount_fs = nfs_remount, | ||
405 | }; | ||
406 | #endif | 319 | #endif |
407 | 320 | ||
408 | static struct shrinker acl_shrinker = { | 321 | static struct shrinker acl_shrinker = { |
@@ -424,18 +337,9 @@ int __init register_nfs_fs(void) | |||
424 | ret = nfs_register_sysctl(); | 337 | ret = nfs_register_sysctl(); |
425 | if (ret < 0) | 338 | if (ret < 0) |
426 | goto error_1; | 339 | goto error_1; |
427 | #ifdef CONFIG_NFS_V4 | ||
428 | ret = register_filesystem(&nfs4_fs_type); | ||
429 | if (ret < 0) | ||
430 | goto error_2; | ||
431 | #endif | ||
432 | register_shrinker(&acl_shrinker); | 340 | register_shrinker(&acl_shrinker); |
433 | return 0; | 341 | return 0; |
434 | 342 | ||
435 | #ifdef CONFIG_NFS_V4 | ||
436 | error_2: | ||
437 | nfs_unregister_sysctl(); | ||
438 | #endif | ||
439 | error_1: | 343 | error_1: |
440 | unregister_filesystem(&nfs_fs_type); | 344 | unregister_filesystem(&nfs_fs_type); |
441 | error_0: | 345 | error_0: |
@@ -448,9 +352,6 @@ error_0: | |||
448 | void __exit unregister_nfs_fs(void) | 352 | void __exit unregister_nfs_fs(void) |
449 | { | 353 | { |
450 | unregister_shrinker(&acl_shrinker); | 354 | unregister_shrinker(&acl_shrinker); |
451 | #ifdef CONFIG_NFS_V4 | ||
452 | unregister_filesystem(&nfs4_fs_type); | ||
453 | #endif | ||
454 | nfs_unregister_sysctl(); | 355 | nfs_unregister_sysctl(); |
455 | unregister_filesystem(&nfs_fs_type); | 356 | unregister_filesystem(&nfs_fs_type); |
456 | } | 357 | } |
@@ -474,7 +375,7 @@ void nfs_sb_deactive(struct super_block *sb) | |||
474 | /* | 375 | /* |
475 | * Deliver file system statistics to userspace | 376 | * Deliver file system statistics to userspace |
476 | */ | 377 | */ |
477 | static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) | 378 | int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) |
478 | { | 379 | { |
479 | struct nfs_server *server = NFS_SB(dentry->d_sb); | 380 | struct nfs_server *server = NFS_SB(dentry->d_sb); |
480 | unsigned char blockbits; | 381 | unsigned char blockbits; |
@@ -757,7 +658,7 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
757 | /* | 658 | /* |
758 | * Describe the mount options on this VFS mountpoint | 659 | * Describe the mount options on this VFS mountpoint |
759 | */ | 660 | */ |
760 | static int nfs_show_options(struct seq_file *m, struct dentry *root) | 661 | int nfs_show_options(struct seq_file *m, struct dentry *root) |
761 | { | 662 | { |
762 | struct nfs_server *nfss = NFS_SB(root->d_sb); | 663 | struct nfs_server *nfss = NFS_SB(root->d_sb); |
763 | 664 | ||
@@ -815,7 +716,7 @@ static void show_implementation_id(struct seq_file *m, struct nfs_server *nfss) | |||
815 | } | 716 | } |
816 | #endif | 717 | #endif |
817 | 718 | ||
818 | static int nfs_show_devname(struct seq_file *m, struct dentry *root) | 719 | int nfs_show_devname(struct seq_file *m, struct dentry *root) |
819 | { | 720 | { |
820 | char *page = (char *) __get_free_page(GFP_KERNEL); | 721 | char *page = (char *) __get_free_page(GFP_KERNEL); |
821 | char *devname, *dummy; | 722 | char *devname, *dummy; |
@@ -831,7 +732,7 @@ static int nfs_show_devname(struct seq_file *m, struct dentry *root) | |||
831 | return err; | 732 | return err; |
832 | } | 733 | } |
833 | 734 | ||
834 | static int nfs_show_path(struct seq_file *m, struct dentry *dentry) | 735 | int nfs_show_path(struct seq_file *m, struct dentry *dentry) |
835 | { | 736 | { |
836 | seq_puts(m, "/"); | 737 | seq_puts(m, "/"); |
837 | return 0; | 738 | return 0; |
@@ -840,7 +741,7 @@ static int nfs_show_path(struct seq_file *m, struct dentry *dentry) | |||
840 | /* | 741 | /* |
841 | * Present statistical information for this VFS mountpoint | 742 | * Present statistical information for this VFS mountpoint |
842 | */ | 743 | */ |
843 | static int nfs_show_stats(struct seq_file *m, struct dentry *root) | 744 | int nfs_show_stats(struct seq_file *m, struct dentry *root) |
844 | { | 745 | { |
845 | int i, cpu; | 746 | int i, cpu; |
846 | struct nfs_server *nfss = NFS_SB(root->d_sb); | 747 | struct nfs_server *nfss = NFS_SB(root->d_sb); |
@@ -933,7 +834,7 @@ static int nfs_show_stats(struct seq_file *m, struct dentry *root) | |||
933 | * Begin unmount by attempting to remove all automounted mountpoints we added | 834 | * Begin unmount by attempting to remove all automounted mountpoints we added |
934 | * in response to xdev traversals and referrals | 835 | * in response to xdev traversals and referrals |
935 | */ | 836 | */ |
936 | static void nfs_umount_begin(struct super_block *sb) | 837 | void nfs_umount_begin(struct super_block *sb) |
937 | { | 838 | { |
938 | struct nfs_server *server; | 839 | struct nfs_server *server; |
939 | struct rpc_clnt *rpc; | 840 | struct rpc_clnt *rpc; |
@@ -2108,7 +2009,7 @@ nfs_compare_remount_data(struct nfs_server *nfss, | |||
2108 | return 0; | 2009 | return 0; |
2109 | } | 2010 | } |
2110 | 2011 | ||
2111 | static int | 2012 | int |
2112 | nfs_remount(struct super_block *sb, int *flags, char *raw_data) | 2013 | nfs_remount(struct super_block *sb, int *flags, char *raw_data) |
2113 | { | 2014 | { |
2114 | int error; | 2015 | int error; |
@@ -2173,7 +2074,7 @@ out: | |||
2173 | /* | 2074 | /* |
2174 | * Initialise the common bits of the superblock | 2075 | * Initialise the common bits of the superblock |
2175 | */ | 2076 | */ |
2176 | static inline void nfs_initialise_sb(struct super_block *sb) | 2077 | inline void nfs_initialise_sb(struct super_block *sb) |
2177 | { | 2078 | { |
2178 | struct nfs_server *server = NFS_SB(sb); | 2079 | struct nfs_server *server = NFS_SB(sb); |
2179 | 2080 | ||
@@ -2195,8 +2096,7 @@ static inline void nfs_initialise_sb(struct super_block *sb) | |||
2195 | /* | 2096 | /* |
2196 | * Finish setting up an NFS2/3 superblock | 2097 | * Finish setting up an NFS2/3 superblock |
2197 | */ | 2098 | */ |
2198 | static void nfs_fill_super(struct super_block *sb, | 2099 | void nfs_fill_super(struct super_block *sb, struct nfs_mount_info *mount_info) |
2199 | struct nfs_mount_info *mount_info) | ||
2200 | { | 2100 | { |
2201 | struct nfs_parsed_mount_data *data = mount_info->parsed; | 2101 | struct nfs_parsed_mount_data *data = mount_info->parsed; |
2202 | struct nfs_server *server = NFS_SB(sb); | 2102 | struct nfs_server *server = NFS_SB(sb); |
@@ -2219,10 +2119,9 @@ static void nfs_fill_super(struct super_block *sb, | |||
2219 | } | 2119 | } |
2220 | 2120 | ||
2221 | /* | 2121 | /* |
2222 | * Finish setting up a cloned NFS2/3 superblock | 2122 | * Finish setting up a cloned NFS2/3/4 superblock |
2223 | */ | 2123 | */ |
2224 | static void nfs_clone_super(struct super_block *sb, | 2124 | void nfs_clone_super(struct super_block *sb, struct nfs_mount_info *mount_info) |
2225 | struct nfs_mount_info *mount_info) | ||
2226 | { | 2125 | { |
2227 | const struct super_block *old_sb = mount_info->cloned->sb; | 2126 | const struct super_block *old_sb = mount_info->cloned->sb; |
2228 | struct nfs_server *server = NFS_SB(sb); | 2127 | struct nfs_server *server = NFS_SB(sb); |
@@ -2230,16 +2129,17 @@ static void nfs_clone_super(struct super_block *sb, | |||
2230 | sb->s_blocksize_bits = old_sb->s_blocksize_bits; | 2129 | sb->s_blocksize_bits = old_sb->s_blocksize_bits; |
2231 | sb->s_blocksize = old_sb->s_blocksize; | 2130 | sb->s_blocksize = old_sb->s_blocksize; |
2232 | sb->s_maxbytes = old_sb->s_maxbytes; | 2131 | sb->s_maxbytes = old_sb->s_maxbytes; |
2132 | sb->s_xattr = old_sb->s_xattr; | ||
2133 | sb->s_op = old_sb->s_op; | ||
2134 | sb->s_time_gran = 1; | ||
2233 | 2135 | ||
2234 | if (server->nfs_client->rpc_ops->version == 3) { | 2136 | if (server->nfs_client->rpc_ops->version != 2) { |
2235 | /* The VFS shouldn't apply the umask to mode bits. We will do | 2137 | /* The VFS shouldn't apply the umask to mode bits. We will do |
2236 | * so ourselves when necessary. | 2138 | * so ourselves when necessary. |
2237 | */ | 2139 | */ |
2238 | sb->s_flags |= MS_POSIXACL; | 2140 | sb->s_flags |= MS_POSIXACL; |
2239 | sb->s_time_gran = 1; | ||
2240 | } | 2141 | } |
2241 | 2142 | ||
2242 | sb->s_op = old_sb->s_op; | ||
2243 | nfs_initialise_sb(sb); | 2143 | nfs_initialise_sb(sb); |
2244 | } | 2144 | } |
2245 | 2145 | ||
@@ -2381,14 +2281,14 @@ static int nfs_bdi_register(struct nfs_server *server) | |||
2381 | return bdi_register_dev(&server->backing_dev_info, server->s_dev); | 2281 | return bdi_register_dev(&server->backing_dev_info, server->s_dev); |
2382 | } | 2282 | } |
2383 | 2283 | ||
2384 | static int nfs_set_sb_security(struct super_block *s, struct dentry *mntroot, | 2284 | int nfs_set_sb_security(struct super_block *s, struct dentry *mntroot, |
2385 | struct nfs_mount_info *mount_info) | 2285 | struct nfs_mount_info *mount_info) |
2386 | { | 2286 | { |
2387 | return security_sb_set_mnt_opts(s, &mount_info->parsed->lsm_opts); | 2287 | return security_sb_set_mnt_opts(s, &mount_info->parsed->lsm_opts); |
2388 | } | 2288 | } |
2389 | 2289 | ||
2390 | static int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot, | 2290 | int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot, |
2391 | struct nfs_mount_info *mount_info) | 2291 | struct nfs_mount_info *mount_info) |
2392 | { | 2292 | { |
2393 | /* clone any lsm security options from the parent to the new sb */ | 2293 | /* clone any lsm security options from the parent to the new sb */ |
2394 | security_sb_clone_mnt_opts(mount_info->cloned->sb, s); | 2294 | security_sb_clone_mnt_opts(mount_info->cloned->sb, s); |
@@ -2397,10 +2297,10 @@ static int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot, | |||
2397 | return 0; | 2297 | return 0; |
2398 | } | 2298 | } |
2399 | 2299 | ||
2400 | static struct dentry *nfs_fs_mount_common(struct file_system_type *fs_type, | 2300 | struct dentry *nfs_fs_mount_common(struct file_system_type *fs_type, |
2401 | struct nfs_server *server, | 2301 | struct nfs_server *server, |
2402 | int flags, const char *dev_name, | 2302 | int flags, const char *dev_name, |
2403 | struct nfs_mount_info *mount_info) | 2303 | struct nfs_mount_info *mount_info) |
2404 | { | 2304 | { |
2405 | struct super_block *s; | 2305 | struct super_block *s; |
2406 | struct dentry *mntroot = ERR_PTR(-ENOMEM); | 2306 | struct dentry *mntroot = ERR_PTR(-ENOMEM); |
@@ -2470,7 +2370,7 @@ error_splat_bdi: | |||
2470 | goto out; | 2370 | goto out; |
2471 | } | 2371 | } |
2472 | 2372 | ||
2473 | static struct dentry *nfs_fs_mount(struct file_system_type *fs_type, | 2373 | struct dentry *nfs_fs_mount(struct file_system_type *fs_type, |
2474 | int flags, const char *dev_name, void *raw_data) | 2374 | int flags, const char *dev_name, void *raw_data) |
2475 | { | 2375 | { |
2476 | struct nfs_mount_info mount_info = { | 2376 | struct nfs_mount_info mount_info = { |
@@ -2511,7 +2411,7 @@ out: | |||
2511 | * Ensure that we unregister the bdi before kill_anon_super | 2411 | * Ensure that we unregister the bdi before kill_anon_super |
2512 | * releases the device name | 2412 | * releases the device name |
2513 | */ | 2413 | */ |
2514 | static void nfs_put_super(struct super_block *s) | 2414 | void nfs_put_super(struct super_block *s) |
2515 | { | 2415 | { |
2516 | struct nfs_server *server = NFS_SB(s); | 2416 | struct nfs_server *server = NFS_SB(s); |
2517 | 2417 | ||
@@ -2521,7 +2421,7 @@ static void nfs_put_super(struct super_block *s) | |||
2521 | /* | 2421 | /* |
2522 | * Destroy an NFS2/3 superblock | 2422 | * Destroy an NFS2/3 superblock |
2523 | */ | 2423 | */ |
2524 | static void nfs_kill_super(struct super_block *s) | 2424 | void nfs_kill_super(struct super_block *s) |
2525 | { | 2425 | { |
2526 | struct nfs_server *server = NFS_SB(s); | 2426 | struct nfs_server *server = NFS_SB(s); |
2527 | 2427 | ||
@@ -2533,7 +2433,7 @@ static void nfs_kill_super(struct super_block *s) | |||
2533 | /* | 2433 | /* |
2534 | * Clone an NFS2/3/4 server record on xdev traversal (FSID-change) | 2434 | * Clone an NFS2/3/4 server record on xdev traversal (FSID-change) |
2535 | */ | 2435 | */ |
2536 | static struct dentry * | 2436 | struct dentry * |
2537 | nfs_xdev_mount_common(struct file_system_type *fs_type, int flags, | 2437 | nfs_xdev_mount_common(struct file_system_type *fs_type, int flags, |
2538 | const char *dev_name, struct nfs_mount_info *mount_info) | 2438 | const char *dev_name, struct nfs_mount_info *mount_info) |
2539 | { | 2439 | { |
@@ -2580,44 +2480,6 @@ nfs_xdev_mount(struct file_system_type *fs_type, int flags, | |||
2580 | 2480 | ||
2581 | #ifdef CONFIG_NFS_V4 | 2481 | #ifdef CONFIG_NFS_V4 |
2582 | 2482 | ||
2583 | /* | ||
2584 | * Finish setting up a cloned NFS4 superblock | ||
2585 | */ | ||
2586 | static void nfs4_clone_super(struct super_block *sb, | ||
2587 | struct nfs_mount_info *mount_info) | ||
2588 | { | ||
2589 | const struct super_block *old_sb = mount_info->cloned->sb; | ||
2590 | sb->s_blocksize_bits = old_sb->s_blocksize_bits; | ||
2591 | sb->s_blocksize = old_sb->s_blocksize; | ||
2592 | sb->s_maxbytes = old_sb->s_maxbytes; | ||
2593 | sb->s_time_gran = 1; | ||
2594 | sb->s_op = old_sb->s_op; | ||
2595 | /* | ||
2596 | * The VFS shouldn't apply the umask to mode bits. We will do | ||
2597 | * so ourselves when necessary. | ||
2598 | */ | ||
2599 | sb->s_flags |= MS_POSIXACL; | ||
2600 | sb->s_xattr = old_sb->s_xattr; | ||
2601 | nfs_initialise_sb(sb); | ||
2602 | } | ||
2603 | |||
2604 | /* | ||
2605 | * Set up an NFS4 superblock | ||
2606 | */ | ||
2607 | static void nfs4_fill_super(struct super_block *sb, | ||
2608 | struct nfs_mount_info *mount_info) | ||
2609 | { | ||
2610 | sb->s_time_gran = 1; | ||
2611 | sb->s_op = &nfs4_sops; | ||
2612 | /* | ||
2613 | * The VFS shouldn't apply the umask to mode bits. We will do | ||
2614 | * so ourselves when necessary. | ||
2615 | */ | ||
2616 | sb->s_flags |= MS_POSIXACL; | ||
2617 | sb->s_xattr = nfs4_xattr_handlers; | ||
2618 | nfs_initialise_sb(sb); | ||
2619 | } | ||
2620 | |||
2621 | static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args) | 2483 | static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args) |
2622 | { | 2484 | { |
2623 | args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3| | 2485 | args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3| |
@@ -2715,250 +2577,4 @@ out_no_address: | |||
2715 | return -EINVAL; | 2577 | return -EINVAL; |
2716 | } | 2578 | } |
2717 | 2579 | ||
2718 | /* | ||
2719 | * Get the superblock for the NFS4 root partition | ||
2720 | */ | ||
2721 | static struct dentry * | ||
2722 | nfs4_remote_mount(struct file_system_type *fs_type, int flags, | ||
2723 | const char *dev_name, void *info) | ||
2724 | { | ||
2725 | struct nfs_mount_info *mount_info = info; | ||
2726 | struct nfs_server *server; | ||
2727 | struct dentry *mntroot = ERR_PTR(-ENOMEM); | ||
2728 | |||
2729 | mount_info->fill_super = nfs4_fill_super; | ||
2730 | mount_info->set_security = nfs_set_sb_security; | ||
2731 | |||
2732 | /* Get a volume representation */ | ||
2733 | server = nfs4_create_server(mount_info->parsed, mount_info->mntfh); | ||
2734 | if (IS_ERR(server)) { | ||
2735 | mntroot = ERR_CAST(server); | ||
2736 | goto out; | ||
2737 | } | ||
2738 | |||
2739 | mntroot = nfs_fs_mount_common(fs_type, server, flags, dev_name, mount_info); | ||
2740 | |||
2741 | out: | ||
2742 | return mntroot; | ||
2743 | } | ||
2744 | |||
2745 | static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type, | ||
2746 | int flags, void *data, const char *hostname) | ||
2747 | { | ||
2748 | struct vfsmount *root_mnt; | ||
2749 | char *root_devname; | ||
2750 | size_t len; | ||
2751 | |||
2752 | len = strlen(hostname) + 5; | ||
2753 | root_devname = kmalloc(len, GFP_KERNEL); | ||
2754 | if (root_devname == NULL) | ||
2755 | return ERR_PTR(-ENOMEM); | ||
2756 | /* Does hostname needs to be enclosed in brackets? */ | ||
2757 | if (strchr(hostname, ':')) | ||
2758 | snprintf(root_devname, len, "[%s]:/", hostname); | ||
2759 | else | ||
2760 | snprintf(root_devname, len, "%s:/", hostname); | ||
2761 | root_mnt = vfs_kern_mount(fs_type, flags, root_devname, data); | ||
2762 | kfree(root_devname); | ||
2763 | return root_mnt; | ||
2764 | } | ||
2765 | |||
2766 | struct nfs_referral_count { | ||
2767 | struct list_head list; | ||
2768 | const struct task_struct *task; | ||
2769 | unsigned int referral_count; | ||
2770 | }; | ||
2771 | |||
2772 | static LIST_HEAD(nfs_referral_count_list); | ||
2773 | static DEFINE_SPINLOCK(nfs_referral_count_list_lock); | ||
2774 | |||
2775 | static struct nfs_referral_count *nfs_find_referral_count(void) | ||
2776 | { | ||
2777 | struct nfs_referral_count *p; | ||
2778 | |||
2779 | list_for_each_entry(p, &nfs_referral_count_list, list) { | ||
2780 | if (p->task == current) | ||
2781 | return p; | ||
2782 | } | ||
2783 | return NULL; | ||
2784 | } | ||
2785 | |||
2786 | #define NFS_MAX_NESTED_REFERRALS 2 | ||
2787 | |||
2788 | static int nfs_referral_loop_protect(void) | ||
2789 | { | ||
2790 | struct nfs_referral_count *p, *new; | ||
2791 | int ret = -ENOMEM; | ||
2792 | |||
2793 | new = kmalloc(sizeof(*new), GFP_KERNEL); | ||
2794 | if (!new) | ||
2795 | goto out; | ||
2796 | new->task = current; | ||
2797 | new->referral_count = 1; | ||
2798 | |||
2799 | ret = 0; | ||
2800 | spin_lock(&nfs_referral_count_list_lock); | ||
2801 | p = nfs_find_referral_count(); | ||
2802 | if (p != NULL) { | ||
2803 | if (p->referral_count >= NFS_MAX_NESTED_REFERRALS) | ||
2804 | ret = -ELOOP; | ||
2805 | else | ||
2806 | p->referral_count++; | ||
2807 | } else { | ||
2808 | list_add(&new->list, &nfs_referral_count_list); | ||
2809 | new = NULL; | ||
2810 | } | ||
2811 | spin_unlock(&nfs_referral_count_list_lock); | ||
2812 | kfree(new); | ||
2813 | out: | ||
2814 | return ret; | ||
2815 | } | ||
2816 | |||
2817 | static void nfs_referral_loop_unprotect(void) | ||
2818 | { | ||
2819 | struct nfs_referral_count *p; | ||
2820 | |||
2821 | spin_lock(&nfs_referral_count_list_lock); | ||
2822 | p = nfs_find_referral_count(); | ||
2823 | p->referral_count--; | ||
2824 | if (p->referral_count == 0) | ||
2825 | list_del(&p->list); | ||
2826 | else | ||
2827 | p = NULL; | ||
2828 | spin_unlock(&nfs_referral_count_list_lock); | ||
2829 | kfree(p); | ||
2830 | } | ||
2831 | |||
2832 | static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt, | ||
2833 | const char *export_path) | ||
2834 | { | ||
2835 | struct dentry *dentry; | ||
2836 | int err; | ||
2837 | |||
2838 | if (IS_ERR(root_mnt)) | ||
2839 | return ERR_CAST(root_mnt); | ||
2840 | |||
2841 | err = nfs_referral_loop_protect(); | ||
2842 | if (err) { | ||
2843 | mntput(root_mnt); | ||
2844 | return ERR_PTR(err); | ||
2845 | } | ||
2846 | |||
2847 | dentry = mount_subtree(root_mnt, export_path); | ||
2848 | nfs_referral_loop_unprotect(); | ||
2849 | |||
2850 | return dentry; | ||
2851 | } | ||
2852 | |||
2853 | static struct dentry *nfs4_try_mount(int flags, const char *dev_name, | ||
2854 | struct nfs_mount_info *mount_info) | ||
2855 | { | ||
2856 | char *export_path; | ||
2857 | struct vfsmount *root_mnt; | ||
2858 | struct dentry *res; | ||
2859 | struct nfs_parsed_mount_data *data = mount_info->parsed; | ||
2860 | |||
2861 | dfprintk(MOUNT, "--> nfs4_try_mount()\n"); | ||
2862 | |||
2863 | mount_info->fill_super = nfs4_fill_super; | ||
2864 | |||
2865 | export_path = data->nfs_server.export_path; | ||
2866 | data->nfs_server.export_path = "/"; | ||
2867 | root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, mount_info, | ||
2868 | data->nfs_server.hostname); | ||
2869 | data->nfs_server.export_path = export_path; | ||
2870 | |||
2871 | res = nfs_follow_remote_path(root_mnt, export_path); | ||
2872 | |||
2873 | dfprintk(MOUNT, "<-- nfs4_try_mount() = %ld%s\n", | ||
2874 | IS_ERR(res) ? PTR_ERR(res) : 0, | ||
2875 | IS_ERR(res) ? " [error]" : ""); | ||
2876 | return res; | ||
2877 | } | ||
2878 | |||
2879 | static void nfs4_kill_super(struct super_block *sb) | ||
2880 | { | ||
2881 | struct nfs_server *server = NFS_SB(sb); | ||
2882 | |||
2883 | dprintk("--> %s\n", __func__); | ||
2884 | nfs_super_return_all_delegations(sb); | ||
2885 | kill_anon_super(sb); | ||
2886 | nfs_fscache_release_super_cookie(sb); | ||
2887 | nfs_free_server(server); | ||
2888 | dprintk("<-- %s\n", __func__); | ||
2889 | } | ||
2890 | |||
2891 | /* | ||
2892 | * Clone an NFS4 server record on xdev traversal (FSID-change) | ||
2893 | */ | ||
2894 | static struct dentry * | ||
2895 | nfs4_xdev_mount(struct file_system_type *fs_type, int flags, | ||
2896 | const char *dev_name, void *raw_data) | ||
2897 | { | ||
2898 | struct nfs_mount_info mount_info = { | ||
2899 | .fill_super = nfs4_clone_super, | ||
2900 | .set_security = nfs_clone_sb_security, | ||
2901 | .cloned = raw_data, | ||
2902 | }; | ||
2903 | return nfs_xdev_mount_common(&nfs4_fs_type, flags, dev_name, &mount_info); | ||
2904 | } | ||
2905 | |||
2906 | static struct dentry * | ||
2907 | nfs4_remote_referral_mount(struct file_system_type *fs_type, int flags, | ||
2908 | const char *dev_name, void *raw_data) | ||
2909 | { | ||
2910 | struct nfs_mount_info mount_info = { | ||
2911 | .fill_super = nfs4_fill_super, | ||
2912 | .set_security = nfs_clone_sb_security, | ||
2913 | .cloned = raw_data, | ||
2914 | }; | ||
2915 | struct nfs_server *server; | ||
2916 | struct dentry *mntroot = ERR_PTR(-ENOMEM); | ||
2917 | |||
2918 | dprintk("--> nfs4_referral_get_sb()\n"); | ||
2919 | |||
2920 | mount_info.mntfh = nfs_alloc_fhandle(); | ||
2921 | if (mount_info.cloned == NULL || mount_info.mntfh == NULL) | ||
2922 | goto out; | ||
2923 | |||
2924 | /* create a new volume representation */ | ||
2925 | server = nfs4_create_referral_server(mount_info.cloned, mount_info.mntfh); | ||
2926 | if (IS_ERR(server)) { | ||
2927 | mntroot = ERR_CAST(server); | ||
2928 | goto out; | ||
2929 | } | ||
2930 | |||
2931 | mntroot = nfs_fs_mount_common(&nfs4_fs_type, server, flags, dev_name, &mount_info); | ||
2932 | out: | ||
2933 | nfs_free_fhandle(mount_info.mntfh); | ||
2934 | return mntroot; | ||
2935 | } | ||
2936 | |||
2937 | /* | ||
2938 | * Create an NFS4 server record on referral traversal | ||
2939 | */ | ||
2940 | static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type, | ||
2941 | int flags, const char *dev_name, void *raw_data) | ||
2942 | { | ||
2943 | struct nfs_clone_mount *data = raw_data; | ||
2944 | char *export_path; | ||
2945 | struct vfsmount *root_mnt; | ||
2946 | struct dentry *res; | ||
2947 | |||
2948 | dprintk("--> nfs4_referral_mount()\n"); | ||
2949 | |||
2950 | export_path = data->mnt_path; | ||
2951 | data->mnt_path = "/"; | ||
2952 | |||
2953 | root_mnt = nfs_do_root_mount(&nfs4_remote_referral_fs_type, | ||
2954 | flags, data, data->hostname); | ||
2955 | data->mnt_path = export_path; | ||
2956 | |||
2957 | res = nfs_follow_remote_path(root_mnt, export_path); | ||
2958 | dprintk("<-- nfs4_referral_mount() = %ld%s\n", | ||
2959 | IS_ERR(res) ? PTR_ERR(res) : 0, | ||
2960 | IS_ERR(res) ? " [error]" : ""); | ||
2961 | return res; | ||
2962 | } | ||
2963 | |||
2964 | #endif /* CONFIG_NFS_V4 */ | 2580 | #endif /* CONFIG_NFS_V4 */ |
diff --git a/fs/nfs/sysctl.c b/fs/nfs/sysctl.c index ad4d2e787b20..6b3f2535a3ec 100644 --- a/fs/nfs/sysctl.c +++ b/fs/nfs/sysctl.c | |||
@@ -9,37 +9,11 @@ | |||
9 | #include <linux/fs.h> | 9 | #include <linux/fs.h> |
10 | #include <linux/sysctl.h> | 10 | #include <linux/sysctl.h> |
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/nfs4.h> | ||
13 | #include <linux/nfs_idmap.h> | ||
14 | #include <linux/nfs_fs.h> | 12 | #include <linux/nfs_fs.h> |
15 | 13 | ||
16 | #include "callback.h" | ||
17 | |||
18 | #ifdef CONFIG_NFS_V4 | ||
19 | static const int nfs_set_port_min = 0; | ||
20 | static const int nfs_set_port_max = 65535; | ||
21 | #endif | ||
22 | static struct ctl_table_header *nfs_callback_sysctl_table; | 14 | static struct ctl_table_header *nfs_callback_sysctl_table; |
23 | 15 | ||
24 | static ctl_table nfs_cb_sysctls[] = { | 16 | static ctl_table nfs_cb_sysctls[] = { |
25 | #ifdef CONFIG_NFS_V4 | ||
26 | { | ||
27 | .procname = "nfs_callback_tcpport", | ||
28 | .data = &nfs_callback_set_tcpport, | ||
29 | .maxlen = sizeof(int), | ||
30 | .mode = 0644, | ||
31 | .proc_handler = proc_dointvec_minmax, | ||
32 | .extra1 = (int *)&nfs_set_port_min, | ||
33 | .extra2 = (int *)&nfs_set_port_max, | ||
34 | }, | ||
35 | { | ||
36 | .procname = "idmap_cache_timeout", | ||
37 | .data = &nfs_idmap_cache_timeout, | ||
38 | .maxlen = sizeof(int), | ||
39 | .mode = 0644, | ||
40 | .proc_handler = proc_dointvec_jiffies, | ||
41 | }, | ||
42 | #endif | ||
43 | { | 17 | { |
44 | .procname = "nfs_mountpoint_timeout", | 18 | .procname = "nfs_mountpoint_timeout", |
45 | .data = &nfs_mountpoint_expiry_timeout, | 19 | .data = &nfs_mountpoint_expiry_timeout, |
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 3210a03342f9..13cea637eff8 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c | |||
@@ -501,7 +501,7 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry) | |||
501 | (unsigned long long)NFS_FILEID(dentry->d_inode)); | 501 | (unsigned long long)NFS_FILEID(dentry->d_inode)); |
502 | 502 | ||
503 | /* Return delegation in anticipation of the rename */ | 503 | /* Return delegation in anticipation of the rename */ |
504 | nfs_inode_return_delegation(dentry->d_inode); | 504 | NFS_PROTO(dentry->d_inode)->return_delegation(dentry->d_inode); |
505 | 505 | ||
506 | sdentry = NULL; | 506 | sdentry = NULL; |
507 | do { | 507 | do { |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 4d6861c0dc14..f312860c15d0 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -336,8 +336,10 @@ static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc | |||
336 | struct nfs_pageio_descriptor pgio; | 336 | struct nfs_pageio_descriptor pgio; |
337 | int err; | 337 | int err; |
338 | 338 | ||
339 | nfs_pageio_init_write(&pgio, page->mapping->host, wb_priority(wbc), | 339 | NFS_PROTO(page->mapping->host)->write_pageio_init(&pgio, |
340 | &nfs_async_write_completion_ops); | 340 | page->mapping->host, |
341 | wb_priority(wbc), | ||
342 | &nfs_async_write_completion_ops); | ||
341 | err = nfs_do_writepage(page, wbc, &pgio); | 343 | err = nfs_do_writepage(page, wbc, &pgio); |
342 | nfs_pageio_complete(&pgio); | 344 | nfs_pageio_complete(&pgio); |
343 | if (err < 0) | 345 | if (err < 0) |
@@ -380,8 +382,7 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) | |||
380 | 382 | ||
381 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES); | 383 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES); |
382 | 384 | ||
383 | nfs_pageio_init_write(&pgio, inode, wb_priority(wbc), | 385 | NFS_PROTO(inode)->write_pageio_init(&pgio, inode, wb_priority(wbc), &nfs_async_write_completion_ops); |
384 | &nfs_async_write_completion_ops); | ||
385 | err = write_cache_pages(mapping, wbc, nfs_writepages_callback, &pgio); | 386 | err = write_cache_pages(mapping, wbc, nfs_writepages_callback, &pgio); |
386 | nfs_pageio_complete(&pgio); | 387 | nfs_pageio_complete(&pgio); |
387 | 388 | ||
@@ -410,7 +411,7 @@ static void nfs_inode_add_request(struct inode *inode, struct nfs_page *req) | |||
410 | nfs_lock_request(req); | 411 | nfs_lock_request(req); |
411 | 412 | ||
412 | spin_lock(&inode->i_lock); | 413 | spin_lock(&inode->i_lock); |
413 | if (!nfsi->npages && nfs_have_delegation(inode, FMODE_WRITE)) | 414 | if (!nfsi->npages && NFS_PROTO(inode)->have_delegation(inode, FMODE_WRITE)) |
414 | inode->i_version++; | 415 | inode->i_version++; |
415 | set_bit(PG_MAPPED, &req->wb_flags); | 416 | set_bit(PG_MAPPED, &req->wb_flags); |
416 | SetPagePrivate(req->wb_page); | 417 | SetPagePrivate(req->wb_page); |
@@ -620,7 +621,7 @@ static void nfs_write_completion(struct nfs_pgio_header *hdr) | |||
620 | goto next; | 621 | goto next; |
621 | } | 622 | } |
622 | if (test_bit(NFS_IOHDR_NEED_COMMIT, &hdr->flags)) { | 623 | if (test_bit(NFS_IOHDR_NEED_COMMIT, &hdr->flags)) { |
623 | memcpy(&req->wb_verf, hdr->verf, sizeof(req->wb_verf)); | 624 | memcpy(&req->wb_verf, &hdr->verf->verifier, sizeof(req->wb_verf)); |
624 | nfs_mark_request_commit(req, hdr->lseg, &cinfo); | 625 | nfs_mark_request_commit(req, hdr->lseg, &cinfo); |
625 | goto next; | 626 | goto next; |
626 | } | 627 | } |
@@ -1202,7 +1203,7 @@ static const struct nfs_pageio_ops nfs_pageio_write_ops = { | |||
1202 | .pg_doio = nfs_generic_pg_writepages, | 1203 | .pg_doio = nfs_generic_pg_writepages, |
1203 | }; | 1204 | }; |
1204 | 1205 | ||
1205 | void nfs_pageio_init_write_mds(struct nfs_pageio_descriptor *pgio, | 1206 | void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, |
1206 | struct inode *inode, int ioflags, | 1207 | struct inode *inode, int ioflags, |
1207 | const struct nfs_pgio_completion_ops *compl_ops) | 1208 | const struct nfs_pgio_completion_ops *compl_ops) |
1208 | { | 1209 | { |
@@ -1217,13 +1218,6 @@ void nfs_pageio_reset_write_mds(struct nfs_pageio_descriptor *pgio) | |||
1217 | } | 1218 | } |
1218 | EXPORT_SYMBOL_GPL(nfs_pageio_reset_write_mds); | 1219 | EXPORT_SYMBOL_GPL(nfs_pageio_reset_write_mds); |
1219 | 1220 | ||
1220 | void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, | ||
1221 | struct inode *inode, int ioflags, | ||
1222 | const struct nfs_pgio_completion_ops *compl_ops) | ||
1223 | { | ||
1224 | if (!pnfs_pageio_init_write(pgio, inode, ioflags, compl_ops)) | ||
1225 | nfs_pageio_init_write_mds(pgio, inode, ioflags, compl_ops); | ||
1226 | } | ||
1227 | 1221 | ||
1228 | void nfs_write_prepare(struct rpc_task *task, void *calldata) | 1222 | void nfs_write_prepare(struct rpc_task *task, void *calldata) |
1229 | { | 1223 | { |
@@ -1547,7 +1541,7 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data) | |||
1547 | 1541 | ||
1548 | /* Okay, COMMIT succeeded, apparently. Check the verifier | 1542 | /* Okay, COMMIT succeeded, apparently. Check the verifier |
1549 | * returned by the server against all stored verfs. */ | 1543 | * returned by the server against all stored verfs. */ |
1550 | if (!memcmp(req->wb_verf.verifier, data->verf.verifier, sizeof(data->verf.verifier))) { | 1544 | if (!memcmp(&req->wb_verf, &data->verf.verifier, sizeof(req->wb_verf))) { |
1551 | /* We have a match */ | 1545 | /* We have a match */ |
1552 | nfs_inode_remove_request(req); | 1546 | nfs_inode_remove_request(req); |
1553 | dprintk(" OK\n"); | 1547 | dprintk(" OK\n"); |
@@ -1677,9 +1671,14 @@ static int nfs_commit_unstable_pages(struct inode *inode, struct writeback_contr | |||
1677 | 1671 | ||
1678 | int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) | 1672 | int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) |
1679 | { | 1673 | { |
1680 | int ret; | 1674 | return nfs_commit_unstable_pages(inode, wbc); |
1675 | } | ||
1676 | |||
1677 | #ifdef CONFIG_NFS_V4 | ||
1678 | int nfs4_write_inode(struct inode *inode, struct writeback_control *wbc) | ||
1679 | { | ||
1680 | int ret = nfs_write_inode(inode, wbc); | ||
1681 | 1681 | ||
1682 | ret = nfs_commit_unstable_pages(inode, wbc); | ||
1683 | if (ret >= 0 && test_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(inode)->flags)) { | 1682 | if (ret >= 0 && test_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(inode)->flags)) { |
1684 | int status; | 1683 | int status; |
1685 | bool sync = true; | 1684 | bool sync = true; |
@@ -1693,6 +1692,7 @@ int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) | |||
1693 | } | 1692 | } |
1694 | return ret; | 1693 | return ret; |
1695 | } | 1694 | } |
1695 | #endif | ||
1696 | 1696 | ||
1697 | /* | 1697 | /* |
1698 | * flush the inode to disk. | 1698 | * flush the inode to disk. |
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index b23cfc120edb..4b6043c20f77 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
@@ -427,10 +427,6 @@ extern __be32 root_nfs_parse_addr(char *name); /*__init*/ | |||
427 | /* | 427 | /* |
428 | * linux/fs/nfs/file.c | 428 | * linux/fs/nfs/file.c |
429 | */ | 429 | */ |
430 | extern const struct inode_operations nfs_file_inode_operations; | ||
431 | #ifdef CONFIG_NFS_V3 | ||
432 | extern const struct inode_operations nfs3_file_inode_operations; | ||
433 | #endif /* CONFIG_NFS_V3 */ | ||
434 | extern const struct file_operations nfs_file_operations; | 430 | extern const struct file_operations nfs_file_operations; |
435 | #ifdef CONFIG_NFS_V4 | 431 | #ifdef CONFIG_NFS_V4 |
436 | extern const struct file_operations nfs4_file_operations; | 432 | extern const struct file_operations nfs4_file_operations; |
@@ -485,10 +481,6 @@ extern ssize_t nfs_file_direct_write(struct kiocb *iocb, | |||
485 | /* | 481 | /* |
486 | * linux/fs/nfs/dir.c | 482 | * linux/fs/nfs/dir.c |
487 | */ | 483 | */ |
488 | extern const struct inode_operations nfs_dir_inode_operations; | ||
489 | #ifdef CONFIG_NFS_V3 | ||
490 | extern const struct inode_operations nfs3_dir_inode_operations; | ||
491 | #endif /* CONFIG_NFS_V3 */ | ||
492 | extern const struct file_operations nfs_dir_operations; | 484 | extern const struct file_operations nfs_dir_operations; |
493 | extern const struct dentry_operations nfs_dentry_operations; | 485 | extern const struct dentry_operations nfs_dentry_operations; |
494 | 486 | ||
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index f58325a1d8fb..65327652c61a 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h | |||
@@ -69,10 +69,9 @@ struct nfs_client { | |||
69 | struct idmap * cl_idmap; | 69 | struct idmap * cl_idmap; |
70 | 70 | ||
71 | /* Our own IP address, as a null-terminated string. | 71 | /* Our own IP address, as a null-terminated string. |
72 | * This is used to generate the clientid, and the callback address. | 72 | * This is used to generate the mv0 callback address. |
73 | */ | 73 | */ |
74 | char cl_ipaddr[48]; | 74 | char cl_ipaddr[48]; |
75 | unsigned char cl_id_uniquifier; | ||
76 | u32 cl_cb_ident; /* v4.0 callback identifier */ | 75 | u32 cl_cb_ident; /* v4.0 callback identifier */ |
77 | const struct nfs4_minor_version_ops *cl_mvops; | 76 | const struct nfs4_minor_version_ops *cl_mvops; |
78 | 77 | ||
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index 88d166b555e8..880805774f9f 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h | |||
@@ -42,7 +42,7 @@ struct nfs_page { | |||
42 | wb_bytes; /* Length of request */ | 42 | wb_bytes; /* Length of request */ |
43 | struct kref wb_kref; /* reference count */ | 43 | struct kref wb_kref; /* reference count */ |
44 | unsigned long wb_flags; | 44 | unsigned long wb_flags; |
45 | struct nfs_writeverf wb_verf; /* Commit cookie */ | 45 | struct nfs_write_verifier wb_verf; /* Commit cookie */ |
46 | }; | 46 | }; |
47 | 47 | ||
48 | struct nfs_pageio_descriptor; | 48 | struct nfs_pageio_descriptor; |
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index d3b7c18b18f4..0e181c2320b7 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h | |||
@@ -514,9 +514,13 @@ struct nfs_writeargs { | |||
514 | struct nfs4_sequence_args seq_args; | 514 | struct nfs4_sequence_args seq_args; |
515 | }; | 515 | }; |
516 | 516 | ||
517 | struct nfs_write_verifier { | ||
518 | char data[8]; | ||
519 | }; | ||
520 | |||
517 | struct nfs_writeverf { | 521 | struct nfs_writeverf { |
522 | struct nfs_write_verifier verifier; | ||
518 | enum nfs3_stable_how committed; | 523 | enum nfs3_stable_how committed; |
519 | __be32 verifier[2]; | ||
520 | }; | 524 | }; |
521 | 525 | ||
522 | struct nfs_writeres { | 526 | struct nfs_writeres { |
@@ -1349,6 +1353,8 @@ struct nfs_renamedata { | |||
1349 | struct nfs_access_entry; | 1353 | struct nfs_access_entry; |
1350 | struct nfs_client; | 1354 | struct nfs_client; |
1351 | struct rpc_timeout; | 1355 | struct rpc_timeout; |
1356 | struct nfs_client_initdata; | ||
1357 | struct nfs_pageio_descriptor; | ||
1352 | 1358 | ||
1353 | /* | 1359 | /* |
1354 | * RPC procedure vector for NFSv2/NFSv3 demuxing | 1360 | * RPC procedure vector for NFSv2/NFSv3 demuxing |
@@ -1402,9 +1408,13 @@ struct nfs_rpc_ops { | |||
1402 | int (*set_capabilities)(struct nfs_server *, struct nfs_fh *); | 1408 | int (*set_capabilities)(struct nfs_server *, struct nfs_fh *); |
1403 | int (*decode_dirent)(struct xdr_stream *, struct nfs_entry *, int); | 1409 | int (*decode_dirent)(struct xdr_stream *, struct nfs_entry *, int); |
1404 | void (*read_setup) (struct nfs_read_data *, struct rpc_message *); | 1410 | void (*read_setup) (struct nfs_read_data *, struct rpc_message *); |
1411 | void (*read_pageio_init)(struct nfs_pageio_descriptor *, struct inode *, | ||
1412 | const struct nfs_pgio_completion_ops *); | ||
1405 | void (*read_rpc_prepare)(struct rpc_task *, struct nfs_read_data *); | 1413 | void (*read_rpc_prepare)(struct rpc_task *, struct nfs_read_data *); |
1406 | int (*read_done) (struct rpc_task *, struct nfs_read_data *); | 1414 | int (*read_done) (struct rpc_task *, struct nfs_read_data *); |
1407 | void (*write_setup) (struct nfs_write_data *, struct rpc_message *); | 1415 | void (*write_setup) (struct nfs_write_data *, struct rpc_message *); |
1416 | void (*write_pageio_init)(struct nfs_pageio_descriptor *, struct inode *, int, | ||
1417 | const struct nfs_pgio_completion_ops *); | ||
1408 | void (*write_rpc_prepare)(struct rpc_task *, struct nfs_write_data *); | 1418 | void (*write_rpc_prepare)(struct rpc_task *, struct nfs_write_data *); |
1409 | int (*write_done) (struct rpc_task *, struct nfs_write_data *); | 1419 | int (*write_done) (struct rpc_task *, struct nfs_write_data *); |
1410 | void (*commit_setup) (struct nfs_commit_data *, struct rpc_message *); | 1420 | void (*commit_setup) (struct nfs_commit_data *, struct rpc_message *); |
@@ -1418,9 +1428,13 @@ struct nfs_rpc_ops { | |||
1418 | struct nfs_open_context *ctx, | 1428 | struct nfs_open_context *ctx, |
1419 | int open_flags, | 1429 | int open_flags, |
1420 | struct iattr *iattr); | 1430 | struct iattr *iattr); |
1431 | int (*have_delegation)(struct inode *, fmode_t); | ||
1432 | int (*return_delegation)(struct inode *); | ||
1433 | struct nfs_client *(*alloc_client) (const struct nfs_client_initdata *); | ||
1421 | struct nfs_client * | 1434 | struct nfs_client * |
1422 | (*init_client) (struct nfs_client *, const struct rpc_timeout *, | 1435 | (*init_client) (struct nfs_client *, const struct rpc_timeout *, |
1423 | const char *, rpc_authflavor_t); | 1436 | const char *, rpc_authflavor_t); |
1437 | void (*free_client) (struct nfs_client *); | ||
1424 | }; | 1438 | }; |
1425 | 1439 | ||
1426 | /* | 1440 | /* |
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index 492a36d72829..f25ba922baaf 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h | |||
@@ -101,6 +101,7 @@ struct rpc_authops { | |||
101 | struct rpc_cred * (*crcreate)(struct rpc_auth*, struct auth_cred *, int); | 101 | struct rpc_cred * (*crcreate)(struct rpc_auth*, struct auth_cred *, int); |
102 | int (*pipes_create)(struct rpc_auth *); | 102 | int (*pipes_create)(struct rpc_auth *); |
103 | void (*pipes_destroy)(struct rpc_auth *); | 103 | void (*pipes_destroy)(struct rpc_auth *); |
104 | int (*list_pseudoflavors)(rpc_authflavor_t *, int); | ||
104 | }; | 105 | }; |
105 | 106 | ||
106 | struct rpc_credops { | 107 | struct rpc_credops { |
@@ -135,6 +136,7 @@ int rpcauth_register(const struct rpc_authops *); | |||
135 | int rpcauth_unregister(const struct rpc_authops *); | 136 | int rpcauth_unregister(const struct rpc_authops *); |
136 | struct rpc_auth * rpcauth_create(rpc_authflavor_t, struct rpc_clnt *); | 137 | struct rpc_auth * rpcauth_create(rpc_authflavor_t, struct rpc_clnt *); |
137 | void rpcauth_release(struct rpc_auth *); | 138 | void rpcauth_release(struct rpc_auth *); |
139 | int rpcauth_list_flavors(rpc_authflavor_t *, int); | ||
138 | struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int); | 140 | struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int); |
139 | void rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *); | 141 | void rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *); |
140 | struct rpc_cred * rpcauth_lookupcred(struct rpc_auth *, int); | 142 | struct rpc_cred * rpcauth_lookupcred(struct rpc_auth *, int); |
diff --git a/include/linux/sunrpc/gss_api.h b/include/linux/sunrpc/gss_api.h index 332da61cf8b7..a19e2547ae6a 100644 --- a/include/linux/sunrpc/gss_api.h +++ b/include/linux/sunrpc/gss_api.h | |||
@@ -14,6 +14,7 @@ | |||
14 | 14 | ||
15 | #ifdef __KERNEL__ | 15 | #ifdef __KERNEL__ |
16 | #include <linux/sunrpc/xdr.h> | 16 | #include <linux/sunrpc/xdr.h> |
17 | #include <linux/sunrpc/msg_prot.h> | ||
17 | #include <linux/uio.h> | 18 | #include <linux/uio.h> |
18 | 19 | ||
19 | /* The mechanism-independent gss-api context: */ | 20 | /* The mechanism-independent gss-api context: */ |
@@ -127,7 +128,7 @@ struct gss_api_mech *gss_mech_get_by_name(const char *); | |||
127 | struct gss_api_mech *gss_mech_get_by_pseudoflavor(u32); | 128 | struct gss_api_mech *gss_mech_get_by_pseudoflavor(u32); |
128 | 129 | ||
129 | /* Fill in an array with a list of supported pseudoflavors */ | 130 | /* Fill in an array with a list of supported pseudoflavors */ |
130 | int gss_mech_list_pseudoflavors(u32 *); | 131 | int gss_mech_list_pseudoflavors(rpc_authflavor_t *, int); |
131 | 132 | ||
132 | /* Just increments the mechanism's reference count and returns its input: */ | 133 | /* Just increments the mechanism's reference count and returns its input: */ |
133 | struct gss_api_mech * gss_mech_get(struct gss_api_mech *); | 134 | struct gss_api_mech * gss_mech_get(struct gss_api_mech *); |
diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index af70af333546..63988990bd36 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h | |||
@@ -104,8 +104,6 @@ __be32 *xdr_decode_string_inplace(__be32 *p, char **sp, unsigned int *lenp, | |||
104 | __be32 *xdr_encode_netobj(__be32 *p, const struct xdr_netobj *); | 104 | __be32 *xdr_encode_netobj(__be32 *p, const struct xdr_netobj *); |
105 | __be32 *xdr_decode_netobj(__be32 *p, struct xdr_netobj *); | 105 | __be32 *xdr_decode_netobj(__be32 *p, struct xdr_netobj *); |
106 | 106 | ||
107 | void xdr_encode_pages(struct xdr_buf *, struct page **, unsigned int, | ||
108 | unsigned int); | ||
109 | void xdr_inline_pages(struct xdr_buf *, unsigned int, | 107 | void xdr_inline_pages(struct xdr_buf *, unsigned int, |
110 | struct page **, unsigned int, unsigned int); | 108 | struct page **, unsigned int, unsigned int); |
111 | void xdr_terminate_string(struct xdr_buf *, const u32); | 109 | void xdr_terminate_string(struct xdr_buf *, const u32); |
@@ -205,6 +203,7 @@ struct xdr_stream { | |||
205 | struct kvec *iov; /* pointer to the current kvec */ | 203 | struct kvec *iov; /* pointer to the current kvec */ |
206 | struct kvec scratch; /* Scratch buffer */ | 204 | struct kvec scratch; /* Scratch buffer */ |
207 | struct page **page_ptr; /* pointer to the current page */ | 205 | struct page **page_ptr; /* pointer to the current page */ |
206 | unsigned int nwords; /* Remaining decode buffer length */ | ||
208 | }; | 207 | }; |
209 | 208 | ||
210 | /* | 209 | /* |
@@ -217,12 +216,13 @@ extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 | |||
217 | extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes); | 216 | extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes); |
218 | extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages, | 217 | extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages, |
219 | unsigned int base, unsigned int len); | 218 | unsigned int base, unsigned int len); |
219 | extern unsigned int xdr_stream_pos(const struct xdr_stream *xdr); | ||
220 | extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p); | 220 | extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p); |
221 | extern void xdr_init_decode_pages(struct xdr_stream *xdr, struct xdr_buf *buf, | 221 | extern void xdr_init_decode_pages(struct xdr_stream *xdr, struct xdr_buf *buf, |
222 | struct page **pages, unsigned int len); | 222 | struct page **pages, unsigned int len); |
223 | extern void xdr_set_scratch_buffer(struct xdr_stream *xdr, void *buf, size_t buflen); | 223 | extern void xdr_set_scratch_buffer(struct xdr_stream *xdr, void *buf, size_t buflen); |
224 | extern __be32 *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes); | 224 | extern __be32 *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes); |
225 | extern void xdr_read_pages(struct xdr_stream *xdr, unsigned int len); | 225 | extern unsigned int xdr_read_pages(struct xdr_stream *xdr, unsigned int len); |
226 | extern void xdr_enter_page(struct xdr_stream *xdr, unsigned int len); | 226 | extern void xdr_enter_page(struct xdr_stream *xdr, unsigned int len); |
227 | extern int xdr_process_buf(struct xdr_buf *buf, unsigned int offset, unsigned int len, int (*actor)(struct scatterlist *, void *), void *data); | 227 | extern int xdr_process_buf(struct xdr_buf *buf, unsigned int offset, unsigned int len, int (*actor)(struct scatterlist *, void *), void *data); |
228 | 228 | ||
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 727e506cacda..b5c067bccc45 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/errno.h> | 13 | #include <linux/errno.h> |
14 | #include <linux/hash.h> | 14 | #include <linux/hash.h> |
15 | #include <linux/sunrpc/clnt.h> | 15 | #include <linux/sunrpc/clnt.h> |
16 | #include <linux/sunrpc/gss_api.h> | ||
16 | #include <linux/spinlock.h> | 17 | #include <linux/spinlock.h> |
17 | 18 | ||
18 | #ifdef RPC_DEBUG | 19 | #ifdef RPC_DEBUG |
@@ -122,6 +123,59 @@ rpcauth_unregister(const struct rpc_authops *ops) | |||
122 | } | 123 | } |
123 | EXPORT_SYMBOL_GPL(rpcauth_unregister); | 124 | EXPORT_SYMBOL_GPL(rpcauth_unregister); |
124 | 125 | ||
126 | /** | ||
127 | * rpcauth_list_flavors - discover registered flavors and pseudoflavors | ||
128 | * @array: array to fill in | ||
129 | * @size: size of "array" | ||
130 | * | ||
131 | * Returns the number of array items filled in, or a negative errno. | ||
132 | * | ||
133 | * The returned array is not sorted by any policy. Callers should not | ||
134 | * rely on the order of the items in the returned array. | ||
135 | */ | ||
136 | int | ||
137 | rpcauth_list_flavors(rpc_authflavor_t *array, int size) | ||
138 | { | ||
139 | rpc_authflavor_t flavor; | ||
140 | int result = 0; | ||
141 | |||
142 | spin_lock(&rpc_authflavor_lock); | ||
143 | for (flavor = 0; flavor < RPC_AUTH_MAXFLAVOR; flavor++) { | ||
144 | const struct rpc_authops *ops = auth_flavors[flavor]; | ||
145 | rpc_authflavor_t pseudos[4]; | ||
146 | int i, len; | ||
147 | |||
148 | if (result >= size) { | ||
149 | result = -ENOMEM; | ||
150 | break; | ||
151 | } | ||
152 | |||
153 | if (ops == NULL) | ||
154 | continue; | ||
155 | if (ops->list_pseudoflavors == NULL) { | ||
156 | array[result++] = ops->au_flavor; | ||
157 | continue; | ||
158 | } | ||
159 | len = ops->list_pseudoflavors(pseudos, ARRAY_SIZE(pseudos)); | ||
160 | if (len < 0) { | ||
161 | result = len; | ||
162 | break; | ||
163 | } | ||
164 | for (i = 0; i < len; i++) { | ||
165 | if (result >= size) { | ||
166 | result = -ENOMEM; | ||
167 | break; | ||
168 | } | ||
169 | array[result++] = pseudos[i]; | ||
170 | } | ||
171 | } | ||
172 | spin_unlock(&rpc_authflavor_lock); | ||
173 | |||
174 | dprintk("RPC: %s returns %d\n", __func__, result); | ||
175 | return result; | ||
176 | } | ||
177 | EXPORT_SYMBOL_GPL(rpcauth_list_flavors); | ||
178 | |||
125 | struct rpc_auth * | 179 | struct rpc_auth * |
126 | rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt) | 180 | rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt) |
127 | { | 181 | { |
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index d3ad81f8da5b..34c522021004 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -1619,6 +1619,7 @@ static const struct rpc_authops authgss_ops = { | |||
1619 | .crcreate = gss_create_cred, | 1619 | .crcreate = gss_create_cred, |
1620 | .pipes_create = gss_pipes_dentries_create, | 1620 | .pipes_create = gss_pipes_dentries_create, |
1621 | .pipes_destroy = gss_pipes_dentries_destroy, | 1621 | .pipes_destroy = gss_pipes_dentries_destroy, |
1622 | .list_pseudoflavors = gss_mech_list_pseudoflavors, | ||
1622 | }; | 1623 | }; |
1623 | 1624 | ||
1624 | static const struct rpc_credops gss_credops = { | 1625 | static const struct rpc_credops gss_credops = { |
diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c index 782bfe1b6465..b174fcd9ff4c 100644 --- a/net/sunrpc/auth_gss/gss_mech_switch.c +++ b/net/sunrpc/auth_gss/gss_mech_switch.c | |||
@@ -239,14 +239,28 @@ gss_mech_get_by_pseudoflavor(u32 pseudoflavor) | |||
239 | 239 | ||
240 | EXPORT_SYMBOL_GPL(gss_mech_get_by_pseudoflavor); | 240 | EXPORT_SYMBOL_GPL(gss_mech_get_by_pseudoflavor); |
241 | 241 | ||
242 | int gss_mech_list_pseudoflavors(rpc_authflavor_t *array_ptr) | 242 | /** |
243 | * gss_mech_list_pseudoflavors - Discover registered GSS pseudoflavors | ||
244 | * @array: array to fill in | ||
245 | * @size: size of "array" | ||
246 | * | ||
247 | * Returns the number of array items filled in, or a negative errno. | ||
248 | * | ||
249 | * The returned array is not sorted by any policy. Callers should not | ||
250 | * rely on the order of the items in the returned array. | ||
251 | */ | ||
252 | int gss_mech_list_pseudoflavors(rpc_authflavor_t *array_ptr, int size) | ||
243 | { | 253 | { |
244 | struct gss_api_mech *pos = NULL; | 254 | struct gss_api_mech *pos = NULL; |
245 | int j, i = 0; | 255 | int j, i = 0; |
246 | 256 | ||
247 | spin_lock(®istered_mechs_lock); | 257 | spin_lock(®istered_mechs_lock); |
248 | list_for_each_entry(pos, ®istered_mechs, gm_list) { | 258 | list_for_each_entry(pos, ®istered_mechs, gm_list) { |
249 | for (j=0; j < pos->gm_pf_num; j++) { | 259 | for (j = 0; j < pos->gm_pf_num; j++) { |
260 | if (i >= size) { | ||
261 | spin_unlock(®istered_mechs_lock); | ||
262 | return -ENOMEM; | ||
263 | } | ||
250 | array_ptr[i++] = pos->gm_pfs[j].pseudoflavor; | 264 | array_ptr[i++] = pos->gm_pfs[j].pseudoflavor; |
251 | } | 265 | } |
252 | } | 266 | } |
@@ -254,8 +268,6 @@ int gss_mech_list_pseudoflavors(rpc_authflavor_t *array_ptr) | |||
254 | return i; | 268 | return i; |
255 | } | 269 | } |
256 | 270 | ||
257 | EXPORT_SYMBOL_GPL(gss_mech_list_pseudoflavors); | ||
258 | |||
259 | u32 | 271 | u32 |
260 | gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 service) | 272 | gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 service) |
261 | { | 273 | { |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 00eb859b7de5..b05df36692ff 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -1844,12 +1844,13 @@ call_timeout(struct rpc_task *task) | |||
1844 | return; | 1844 | return; |
1845 | } | 1845 | } |
1846 | if (RPC_IS_SOFT(task)) { | 1846 | if (RPC_IS_SOFT(task)) { |
1847 | if (clnt->cl_chatty) | 1847 | if (clnt->cl_chatty) { |
1848 | rcu_read_lock(); | 1848 | rcu_read_lock(); |
1849 | printk(KERN_NOTICE "%s: server %s not responding, timed out\n", | 1849 | printk(KERN_NOTICE "%s: server %s not responding, timed out\n", |
1850 | clnt->cl_protname, | 1850 | clnt->cl_protname, |
1851 | rcu_dereference(clnt->cl_xprt)->servername); | 1851 | rcu_dereference(clnt->cl_xprt)->servername); |
1852 | rcu_read_unlock(); | 1852 | rcu_read_unlock(); |
1853 | } | ||
1853 | if (task->tk_flags & RPC_TASK_TIMEOUT) | 1854 | if (task->tk_flags & RPC_TASK_TIMEOUT) |
1854 | rpc_exit(task, -ETIMEDOUT); | 1855 | rpc_exit(task, -ETIMEDOUT); |
1855 | else | 1856 | else |
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index 0cf165580d8d..0afba1b4b656 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c | |||
@@ -129,34 +129,6 @@ xdr_terminate_string(struct xdr_buf *buf, const u32 len) | |||
129 | EXPORT_SYMBOL_GPL(xdr_terminate_string); | 129 | EXPORT_SYMBOL_GPL(xdr_terminate_string); |
130 | 130 | ||
131 | void | 131 | void |
132 | xdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base, | ||
133 | unsigned int len) | ||
134 | { | ||
135 | struct kvec *tail = xdr->tail; | ||
136 | u32 *p; | ||
137 | |||
138 | xdr->pages = pages; | ||
139 | xdr->page_base = base; | ||
140 | xdr->page_len = len; | ||
141 | |||
142 | p = (u32 *)xdr->head[0].iov_base + XDR_QUADLEN(xdr->head[0].iov_len); | ||
143 | tail->iov_base = p; | ||
144 | tail->iov_len = 0; | ||
145 | |||
146 | if (len & 3) { | ||
147 | unsigned int pad = 4 - (len & 3); | ||
148 | |||
149 | *p = 0; | ||
150 | tail->iov_base = (char *)p + (len & 3); | ||
151 | tail->iov_len = pad; | ||
152 | len += pad; | ||
153 | } | ||
154 | xdr->buflen += len; | ||
155 | xdr->len += len; | ||
156 | } | ||
157 | EXPORT_SYMBOL_GPL(xdr_encode_pages); | ||
158 | |||
159 | void | ||
160 | xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset, | 132 | xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset, |
161 | struct page **pages, unsigned int base, unsigned int len) | 133 | struct page **pages, unsigned int base, unsigned int len) |
162 | { | 134 | { |
@@ -457,6 +429,16 @@ xdr_shift_buf(struct xdr_buf *buf, size_t len) | |||
457 | EXPORT_SYMBOL_GPL(xdr_shift_buf); | 429 | EXPORT_SYMBOL_GPL(xdr_shift_buf); |
458 | 430 | ||
459 | /** | 431 | /** |
432 | * xdr_stream_pos - Return the current offset from the start of the xdr_stream | ||
433 | * @xdr: pointer to struct xdr_stream | ||
434 | */ | ||
435 | unsigned int xdr_stream_pos(const struct xdr_stream *xdr) | ||
436 | { | ||
437 | return (unsigned int)(XDR_QUADLEN(xdr->buf->len) - xdr->nwords) << 2; | ||
438 | } | ||
439 | EXPORT_SYMBOL_GPL(xdr_stream_pos); | ||
440 | |||
441 | /** | ||
460 | * xdr_init_encode - Initialize a struct xdr_stream for sending data. | 442 | * xdr_init_encode - Initialize a struct xdr_stream for sending data. |
461 | * @xdr: pointer to xdr_stream struct | 443 | * @xdr: pointer to xdr_stream struct |
462 | * @buf: pointer to XDR buffer in which to encode data | 444 | * @buf: pointer to XDR buffer in which to encode data |
@@ -556,13 +538,11 @@ void xdr_write_pages(struct xdr_stream *xdr, struct page **pages, unsigned int b | |||
556 | EXPORT_SYMBOL_GPL(xdr_write_pages); | 538 | EXPORT_SYMBOL_GPL(xdr_write_pages); |
557 | 539 | ||
558 | static void xdr_set_iov(struct xdr_stream *xdr, struct kvec *iov, | 540 | static void xdr_set_iov(struct xdr_stream *xdr, struct kvec *iov, |
559 | __be32 *p, unsigned int len) | 541 | unsigned int len) |
560 | { | 542 | { |
561 | if (len > iov->iov_len) | 543 | if (len > iov->iov_len) |
562 | len = iov->iov_len; | 544 | len = iov->iov_len; |
563 | if (p == NULL) | 545 | xdr->p = (__be32*)iov->iov_base; |
564 | p = (__be32*)iov->iov_base; | ||
565 | xdr->p = p; | ||
566 | xdr->end = (__be32*)(iov->iov_base + len); | 546 | xdr->end = (__be32*)(iov->iov_base + len); |
567 | xdr->iov = iov; | 547 | xdr->iov = iov; |
568 | xdr->page_ptr = NULL; | 548 | xdr->page_ptr = NULL; |
@@ -609,7 +589,7 @@ static void xdr_set_next_page(struct xdr_stream *xdr) | |||
609 | newbase -= xdr->buf->page_base; | 589 | newbase -= xdr->buf->page_base; |
610 | 590 | ||
611 | if (xdr_set_page_base(xdr, newbase, PAGE_SIZE) < 0) | 591 | if (xdr_set_page_base(xdr, newbase, PAGE_SIZE) < 0) |
612 | xdr_set_iov(xdr, xdr->buf->tail, NULL, xdr->buf->len); | 592 | xdr_set_iov(xdr, xdr->buf->tail, xdr->buf->len); |
613 | } | 593 | } |
614 | 594 | ||
615 | static bool xdr_set_next_buffer(struct xdr_stream *xdr) | 595 | static bool xdr_set_next_buffer(struct xdr_stream *xdr) |
@@ -618,7 +598,7 @@ static bool xdr_set_next_buffer(struct xdr_stream *xdr) | |||
618 | xdr_set_next_page(xdr); | 598 | xdr_set_next_page(xdr); |
619 | else if (xdr->iov == xdr->buf->head) { | 599 | else if (xdr->iov == xdr->buf->head) { |
620 | if (xdr_set_page_base(xdr, 0, PAGE_SIZE) < 0) | 600 | if (xdr_set_page_base(xdr, 0, PAGE_SIZE) < 0) |
621 | xdr_set_iov(xdr, xdr->buf->tail, NULL, xdr->buf->len); | 601 | xdr_set_iov(xdr, xdr->buf->tail, xdr->buf->len); |
622 | } | 602 | } |
623 | return xdr->p != xdr->end; | 603 | return xdr->p != xdr->end; |
624 | } | 604 | } |
@@ -634,10 +614,15 @@ void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p) | |||
634 | xdr->buf = buf; | 614 | xdr->buf = buf; |
635 | xdr->scratch.iov_base = NULL; | 615 | xdr->scratch.iov_base = NULL; |
636 | xdr->scratch.iov_len = 0; | 616 | xdr->scratch.iov_len = 0; |
617 | xdr->nwords = XDR_QUADLEN(buf->len); | ||
637 | if (buf->head[0].iov_len != 0) | 618 | if (buf->head[0].iov_len != 0) |
638 | xdr_set_iov(xdr, buf->head, p, buf->len); | 619 | xdr_set_iov(xdr, buf->head, buf->len); |
639 | else if (buf->page_len != 0) | 620 | else if (buf->page_len != 0) |
640 | xdr_set_page_base(xdr, 0, buf->len); | 621 | xdr_set_page_base(xdr, 0, buf->len); |
622 | if (p != NULL && p > xdr->p && xdr->end >= p) { | ||
623 | xdr->nwords -= p - xdr->p; | ||
624 | xdr->p = p; | ||
625 | } | ||
641 | } | 626 | } |
642 | EXPORT_SYMBOL_GPL(xdr_init_decode); | 627 | EXPORT_SYMBOL_GPL(xdr_init_decode); |
643 | 628 | ||
@@ -662,12 +647,14 @@ EXPORT_SYMBOL_GPL(xdr_init_decode_pages); | |||
662 | 647 | ||
663 | static __be32 * __xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes) | 648 | static __be32 * __xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes) |
664 | { | 649 | { |
650 | unsigned int nwords = XDR_QUADLEN(nbytes); | ||
665 | __be32 *p = xdr->p; | 651 | __be32 *p = xdr->p; |
666 | __be32 *q = p + XDR_QUADLEN(nbytes); | 652 | __be32 *q = p + nwords; |
667 | 653 | ||
668 | if (unlikely(q > xdr->end || q < p)) | 654 | if (unlikely(nwords > xdr->nwords || q > xdr->end || q < p)) |
669 | return NULL; | 655 | return NULL; |
670 | xdr->p = q; | 656 | xdr->p = q; |
657 | xdr->nwords -= nwords; | ||
671 | return p; | 658 | return p; |
672 | } | 659 | } |
673 | 660 | ||
@@ -734,6 +721,31 @@ __be32 * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes) | |||
734 | } | 721 | } |
735 | EXPORT_SYMBOL_GPL(xdr_inline_decode); | 722 | EXPORT_SYMBOL_GPL(xdr_inline_decode); |
736 | 723 | ||
724 | static unsigned int xdr_align_pages(struct xdr_stream *xdr, unsigned int len) | ||
725 | { | ||
726 | struct xdr_buf *buf = xdr->buf; | ||
727 | struct kvec *iov; | ||
728 | unsigned int nwords = XDR_QUADLEN(len); | ||
729 | unsigned int cur = xdr_stream_pos(xdr); | ||
730 | |||
731 | if (xdr->nwords == 0) | ||
732 | return 0; | ||
733 | if (nwords > xdr->nwords) { | ||
734 | nwords = xdr->nwords; | ||
735 | len = nwords << 2; | ||
736 | } | ||
737 | /* Realign pages to current pointer position */ | ||
738 | iov = buf->head; | ||
739 | if (iov->iov_len > cur) | ||
740 | xdr_shrink_bufhead(buf, iov->iov_len - cur); | ||
741 | |||
742 | /* Truncate page data and move it into the tail */ | ||
743 | if (buf->page_len > len) | ||
744 | xdr_shrink_pagelen(buf, buf->page_len - len); | ||
745 | xdr->nwords = XDR_QUADLEN(buf->len - cur); | ||
746 | return len; | ||
747 | } | ||
748 | |||
737 | /** | 749 | /** |
738 | * xdr_read_pages - Ensure page-based XDR data to decode is aligned at current pointer position | 750 | * xdr_read_pages - Ensure page-based XDR data to decode is aligned at current pointer position |
739 | * @xdr: pointer to xdr_stream struct | 751 | * @xdr: pointer to xdr_stream struct |
@@ -742,39 +754,37 @@ EXPORT_SYMBOL_GPL(xdr_inline_decode); | |||
742 | * Moves data beyond the current pointer position from the XDR head[] buffer | 754 | * Moves data beyond the current pointer position from the XDR head[] buffer |
743 | * into the page list. Any data that lies beyond current position + "len" | 755 | * into the page list. Any data that lies beyond current position + "len" |
744 | * bytes is moved into the XDR tail[]. | 756 | * bytes is moved into the XDR tail[]. |
757 | * | ||
758 | * Returns the number of XDR encoded bytes now contained in the pages | ||
745 | */ | 759 | */ |
746 | void xdr_read_pages(struct xdr_stream *xdr, unsigned int len) | 760 | unsigned int xdr_read_pages(struct xdr_stream *xdr, unsigned int len) |
747 | { | 761 | { |
748 | struct xdr_buf *buf = xdr->buf; | 762 | struct xdr_buf *buf = xdr->buf; |
749 | struct kvec *iov; | 763 | struct kvec *iov; |
750 | ssize_t shift; | 764 | unsigned int nwords; |
751 | unsigned int end; | 765 | unsigned int end; |
752 | int padding; | 766 | unsigned int padding; |
753 | 767 | ||
754 | /* Realign pages to current pointer position */ | 768 | len = xdr_align_pages(xdr, len); |
755 | iov = buf->head; | 769 | if (len == 0) |
756 | shift = iov->iov_len + (char *)iov->iov_base - (char *)xdr->p; | 770 | return 0; |
757 | if (shift > 0) | 771 | nwords = XDR_QUADLEN(len); |
758 | xdr_shrink_bufhead(buf, shift); | 772 | padding = (nwords << 2) - len; |
759 | |||
760 | /* Truncate page data and move it into the tail */ | ||
761 | if (buf->page_len > len) | ||
762 | xdr_shrink_pagelen(buf, buf->page_len - len); | ||
763 | padding = (XDR_QUADLEN(len) << 2) - len; | ||
764 | xdr->iov = iov = buf->tail; | 773 | xdr->iov = iov = buf->tail; |
765 | /* Compute remaining message length. */ | 774 | /* Compute remaining message length. */ |
766 | end = iov->iov_len; | 775 | end = ((xdr->nwords - nwords) << 2) + padding; |
767 | shift = buf->buflen - buf->len; | 776 | if (end > iov->iov_len) |
768 | if (shift < end) | 777 | end = iov->iov_len; |
769 | end -= shift; | 778 | |
770 | else if (shift > 0) | ||
771 | end = 0; | ||
772 | /* | 779 | /* |
773 | * Position current pointer at beginning of tail, and | 780 | * Position current pointer at beginning of tail, and |
774 | * set remaining message length. | 781 | * set remaining message length. |
775 | */ | 782 | */ |
776 | xdr->p = (__be32 *)((char *)iov->iov_base + padding); | 783 | xdr->p = (__be32 *)((char *)iov->iov_base + padding); |
777 | xdr->end = (__be32 *)((char *)iov->iov_base + end); | 784 | xdr->end = (__be32 *)((char *)iov->iov_base + end); |
785 | xdr->page_ptr = NULL; | ||
786 | xdr->nwords = XDR_QUADLEN(end - padding); | ||
787 | return len; | ||
778 | } | 788 | } |
779 | EXPORT_SYMBOL_GPL(xdr_read_pages); | 789 | EXPORT_SYMBOL_GPL(xdr_read_pages); |
780 | 790 | ||
@@ -790,12 +800,13 @@ EXPORT_SYMBOL_GPL(xdr_read_pages); | |||
790 | */ | 800 | */ |
791 | void xdr_enter_page(struct xdr_stream *xdr, unsigned int len) | 801 | void xdr_enter_page(struct xdr_stream *xdr, unsigned int len) |
792 | { | 802 | { |
793 | xdr_read_pages(xdr, len); | 803 | len = xdr_align_pages(xdr, len); |
794 | /* | 804 | /* |
795 | * Position current pointer at beginning of tail, and | 805 | * Position current pointer at beginning of tail, and |
796 | * set remaining message length. | 806 | * set remaining message length. |
797 | */ | 807 | */ |
798 | xdr_set_page_base(xdr, 0, len); | 808 | if (len != 0) |
809 | xdr_set_page_base(xdr, 0, len); | ||
799 | } | 810 | } |
800 | EXPORT_SYMBOL_GPL(xdr_enter_page); | 811 | EXPORT_SYMBOL_GPL(xdr_enter_page); |
801 | 812 | ||