diff options
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 | ||
