diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-01-30 03:54:24 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-01-30 03:54:24 -0500 |
| commit | 85004cc367abc000aa36c0d0e270ab609a68b0cb (patch) | |
| tree | 5739aae778d67b6d119fe5c668313fc2823e9836 | |
| parent | 149a051f82d2b3860fe32fa182dbc83a66274894 (diff) | |
| parent | 3fbd67ad61f6d5a09ea717b56c50bc5c3d8042a8 (diff) | |
Merge git://git.linux-nfs.org/pub/linux/nfs-2.6
* git://git.linux-nfs.org/pub/linux/nfs-2.6: (118 commits)
NFSv4: Iterate through all nfs_clients when the server recalls a delegation
NFSv4: Deal more correctly with duplicate delegations
NFS: Fix a potential race between umount and nfs_access_cache_shrinker()
NFS: Add an asynchronous delegreturn operation for use in nfs_clear_inode
nfs: convert NFS_*(inode) helpers to static inline
nfs: obliterate NFS_FLAGS macro
NFS: Address memory leaks in the NFS client mount option parser
nfs4: allow nfsv4 acls on non-regular-files
NFS: Optimise away the sigmask code in aio/dio reads and writes
SUNRPC: Don't bother changing the sigmask for asynchronous RPC calls
SUNRPC: rpcb_getport_sync() passes incorrect address size to rpc_create()
SUNRPC: Clean up block comment preceding rpcb_getport_sync()
SUNRPC: Use appropriate argument types in rpcb client
SUNRPC: rpcb_getport_sync() should use built-in hostname generator
SUNRPC: Clean up functions that free address_strings array
NFS: NFS version number is unsigned
NLM: Fix a bogus 'return' in nlmclnt_rpc_release
NLM: Introduce an arguments structure for nlmclnt_init()
NLM/NFS: Use cached nlm_host when calling nlmclnt_proc()
NFS: Invoke nlmclnt_init during NFS mount processing
...
55 files changed, 1910 insertions, 1293 deletions
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index d070b18e539d..0b45fd3a4bfd 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c | |||
| @@ -41,6 +41,48 @@ struct nlm_wait { | |||
| 41 | 41 | ||
| 42 | static LIST_HEAD(nlm_blocked); | 42 | static LIST_HEAD(nlm_blocked); |
| 43 | 43 | ||
| 44 | /** | ||
| 45 | * nlmclnt_init - Set up per-NFS mount point lockd data structures | ||
| 46 | * @nlm_init: pointer to arguments structure | ||
| 47 | * | ||
| 48 | * Returns pointer to an appropriate nlm_host struct, | ||
| 49 | * or an ERR_PTR value. | ||
| 50 | */ | ||
| 51 | struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init) | ||
| 52 | { | ||
| 53 | struct nlm_host *host; | ||
| 54 | u32 nlm_version = (nlm_init->nfs_version == 2) ? 1 : 4; | ||
| 55 | int status; | ||
| 56 | |||
| 57 | status = lockd_up(nlm_init->protocol); | ||
| 58 | if (status < 0) | ||
| 59 | return ERR_PTR(status); | ||
| 60 | |||
| 61 | host = nlmclnt_lookup_host((struct sockaddr_in *)nlm_init->address, | ||
| 62 | nlm_init->protocol, nlm_version, | ||
| 63 | nlm_init->hostname, | ||
| 64 | strlen(nlm_init->hostname)); | ||
| 65 | if (host == NULL) { | ||
| 66 | lockd_down(); | ||
| 67 | return ERR_PTR(-ENOLCK); | ||
| 68 | } | ||
| 69 | |||
| 70 | return host; | ||
| 71 | } | ||
| 72 | EXPORT_SYMBOL_GPL(nlmclnt_init); | ||
| 73 | |||
| 74 | /** | ||
| 75 | * nlmclnt_done - Release resources allocated by nlmclnt_init() | ||
| 76 | * @host: nlm_host structure reserved by nlmclnt_init() | ||
| 77 | * | ||
| 78 | */ | ||
| 79 | void nlmclnt_done(struct nlm_host *host) | ||
| 80 | { | ||
| 81 | nlm_release_host(host); | ||
| 82 | lockd_down(); | ||
| 83 | } | ||
| 84 | EXPORT_SYMBOL_GPL(nlmclnt_done); | ||
| 85 | |||
| 44 | /* | 86 | /* |
| 45 | * Queue up a lock for blocking so that the GRANTED request can see it | 87 | * Queue up a lock for blocking so that the GRANTED request can see it |
| 46 | */ | 88 | */ |
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index a10343bed160..b6b74a60e1eb 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c | |||
| @@ -145,34 +145,21 @@ static void nlmclnt_release_lockargs(struct nlm_rqst *req) | |||
| 145 | BUG_ON(req->a_args.lock.fl.fl_ops != NULL); | 145 | BUG_ON(req->a_args.lock.fl.fl_ops != NULL); |
| 146 | } | 146 | } |
| 147 | 147 | ||
| 148 | /* | 148 | /** |
| 149 | * This is the main entry point for the NLM client. | 149 | * nlmclnt_proc - Perform a single client-side lock request |
| 150 | * @host: address of a valid nlm_host context representing the NLM server | ||
| 151 | * @cmd: fcntl-style file lock operation to perform | ||
| 152 | * @fl: address of arguments for the lock operation | ||
| 153 | * | ||
| 150 | */ | 154 | */ |
| 151 | int | 155 | int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) |
| 152 | nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) | ||
| 153 | { | 156 | { |
| 154 | struct rpc_clnt *client = NFS_CLIENT(inode); | ||
| 155 | struct sockaddr_in addr; | ||
| 156 | struct nfs_server *nfssrv = NFS_SERVER(inode); | ||
| 157 | struct nlm_host *host; | ||
| 158 | struct nlm_rqst *call; | 157 | struct nlm_rqst *call; |
| 159 | sigset_t oldset; | 158 | sigset_t oldset; |
| 160 | unsigned long flags; | 159 | unsigned long flags; |
| 161 | int status, vers; | 160 | int status; |
| 162 | |||
| 163 | vers = (NFS_PROTO(inode)->version == 3) ? 4 : 1; | ||
| 164 | if (NFS_PROTO(inode)->version > 3) { | ||
| 165 | printk(KERN_NOTICE "NFSv4 file locking not implemented!\n"); | ||
| 166 | return -ENOLCK; | ||
| 167 | } | ||
| 168 | |||
| 169 | rpc_peeraddr(client, (struct sockaddr *) &addr, sizeof(addr)); | ||
| 170 | host = nlmclnt_lookup_host(&addr, client->cl_xprt->prot, vers, | ||
| 171 | nfssrv->nfs_client->cl_hostname, | ||
| 172 | strlen(nfssrv->nfs_client->cl_hostname)); | ||
| 173 | if (host == NULL) | ||
| 174 | return -ENOLCK; | ||
| 175 | 161 | ||
| 162 | nlm_get_host(host); | ||
| 176 | call = nlm_alloc_call(host); | 163 | call = nlm_alloc_call(host); |
| 177 | if (call == NULL) | 164 | if (call == NULL) |
| 178 | return -ENOMEM; | 165 | return -ENOMEM; |
| @@ -219,7 +206,7 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) | |||
| 219 | dprintk("lockd: clnt proc returns %d\n", status); | 206 | dprintk("lockd: clnt proc returns %d\n", status); |
| 220 | return status; | 207 | return status; |
| 221 | } | 208 | } |
| 222 | EXPORT_SYMBOL(nlmclnt_proc); | 209 | EXPORT_SYMBOL_GPL(nlmclnt_proc); |
| 223 | 210 | ||
| 224 | /* | 211 | /* |
| 225 | * Allocate an NLM RPC call struct | 212 | * Allocate an NLM RPC call struct |
| @@ -257,7 +244,7 @@ void nlm_release_call(struct nlm_rqst *call) | |||
| 257 | 244 | ||
| 258 | static void nlmclnt_rpc_release(void *data) | 245 | static void nlmclnt_rpc_release(void *data) |
| 259 | { | 246 | { |
| 260 | return nlm_release_call(data); | 247 | nlm_release_call(data); |
| 261 | } | 248 | } |
| 262 | 249 | ||
| 263 | static int nlm_wait_on_grace(wait_queue_head_t *queue) | 250 | static int nlm_wait_on_grace(wait_queue_head_t *queue) |
diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c index 633653bff944..3e459e18cc31 100644 --- a/fs/lockd/xdr.c +++ b/fs/lockd/xdr.c | |||
| @@ -612,8 +612,7 @@ const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie) | |||
| 612 | * called with BKL held. | 612 | * called with BKL held. |
| 613 | */ | 613 | */ |
| 614 | static char buf[2*NLM_MAXCOOKIELEN+1]; | 614 | static char buf[2*NLM_MAXCOOKIELEN+1]; |
| 615 | int i; | 615 | unsigned int i, len = sizeof(buf); |
| 616 | int len = sizeof(buf); | ||
| 617 | char *p = buf; | 616 | char *p = buf; |
| 618 | 617 | ||
| 619 | len--; /* allow for trailing \0 */ | 618 | len--; /* allow for trailing \0 */ |
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index a796be5051bf..9b6bbf1b9787 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
| @@ -73,8 +73,6 @@ static void nfs_callback_svc(struct svc_rqst *rqstp) | |||
| 73 | complete(&nfs_callback_info.started); | 73 | complete(&nfs_callback_info.started); |
| 74 | 74 | ||
| 75 | for(;;) { | 75 | for(;;) { |
| 76 | char buf[RPC_MAX_ADDRBUFLEN]; | ||
| 77 | |||
| 78 | if (signalled()) { | 76 | if (signalled()) { |
| 79 | if (nfs_callback_info.users == 0) | 77 | if (nfs_callback_info.users == 0) |
| 80 | break; | 78 | break; |
| @@ -92,8 +90,6 @@ static void nfs_callback_svc(struct svc_rqst *rqstp) | |||
| 92 | __FUNCTION__, -err); | 90 | __FUNCTION__, -err); |
| 93 | break; | 91 | break; |
| 94 | } | 92 | } |
| 95 | dprintk("%s: request from %s\n", __FUNCTION__, | ||
| 96 | svc_print_addr(rqstp, buf, sizeof(buf))); | ||
| 97 | svc_process(rqstp); | 93 | svc_process(rqstp); |
| 98 | } | 94 | } |
| 99 | 95 | ||
| @@ -168,12 +164,11 @@ void nfs_callback_down(void) | |||
| 168 | 164 | ||
| 169 | static int nfs_callback_authenticate(struct svc_rqst *rqstp) | 165 | static int nfs_callback_authenticate(struct svc_rqst *rqstp) |
| 170 | { | 166 | { |
| 171 | struct sockaddr_in *addr = svc_addr_in(rqstp); | ||
| 172 | struct nfs_client *clp; | 167 | struct nfs_client *clp; |
| 173 | char buf[RPC_MAX_ADDRBUFLEN]; | 168 | char buf[RPC_MAX_ADDRBUFLEN]; |
| 174 | 169 | ||
| 175 | /* Don't talk to strangers */ | 170 | /* Don't talk to strangers */ |
| 176 | clp = nfs_find_client(addr, 4); | 171 | clp = nfs_find_client(svc_addr(rqstp), 4); |
| 177 | if (clp == NULL) | 172 | if (clp == NULL) |
| 178 | return SVC_DROP; | 173 | return SVC_DROP; |
| 179 | 174 | ||
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h index c2bb14e053e1..bb25d2135ff1 100644 --- a/fs/nfs/callback.h +++ b/fs/nfs/callback.h | |||
| @@ -38,7 +38,7 @@ struct cb_compound_hdr_res { | |||
| 38 | }; | 38 | }; |
| 39 | 39 | ||
| 40 | struct cb_getattrargs { | 40 | struct cb_getattrargs { |
| 41 | struct sockaddr_in *addr; | 41 | struct sockaddr *addr; |
| 42 | struct nfs_fh fh; | 42 | struct nfs_fh fh; |
| 43 | uint32_t bitmap[2]; | 43 | uint32_t bitmap[2]; |
| 44 | }; | 44 | }; |
| @@ -53,7 +53,7 @@ struct cb_getattrres { | |||
| 53 | }; | 53 | }; |
| 54 | 54 | ||
| 55 | struct cb_recallargs { | 55 | struct cb_recallargs { |
| 56 | struct sockaddr_in *addr; | 56 | struct sockaddr *addr; |
| 57 | struct nfs_fh fh; | 57 | struct nfs_fh fh; |
| 58 | nfs4_stateid stateid; | 58 | nfs4_stateid stateid; |
| 59 | uint32_t truncate; | 59 | uint32_t truncate; |
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 72e55d83756d..15f7785048d3 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
| @@ -12,7 +12,9 @@ | |||
| 12 | #include "delegation.h" | 12 | #include "delegation.h" |
| 13 | #include "internal.h" | 13 | #include "internal.h" |
| 14 | 14 | ||
| 15 | #ifdef NFS_DEBUG | ||
| 15 | #define NFSDBG_FACILITY NFSDBG_CALLBACK | 16 | #define NFSDBG_FACILITY NFSDBG_CALLBACK |
| 17 | #endif | ||
| 16 | 18 | ||
| 17 | __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res) | 19 | __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res) |
| 18 | { | 20 | { |
| @@ -20,12 +22,16 @@ __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres * | |||
| 20 | struct nfs_delegation *delegation; | 22 | struct nfs_delegation *delegation; |
| 21 | struct nfs_inode *nfsi; | 23 | struct nfs_inode *nfsi; |
| 22 | struct inode *inode; | 24 | struct inode *inode; |
| 23 | 25 | ||
| 24 | res->bitmap[0] = res->bitmap[1] = 0; | 26 | res->bitmap[0] = res->bitmap[1] = 0; |
| 25 | res->status = htonl(NFS4ERR_BADHANDLE); | 27 | res->status = htonl(NFS4ERR_BADHANDLE); |
| 26 | clp = nfs_find_client(args->addr, 4); | 28 | clp = nfs_find_client(args->addr, 4); |
| 27 | if (clp == NULL) | 29 | if (clp == NULL) |
| 28 | goto out; | 30 | goto out; |
| 31 | |||
| 32 | dprintk("NFS: GETATTR callback request from %s\n", | ||
| 33 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR)); | ||
| 34 | |||
| 29 | inode = nfs_delegation_find_inode(clp, &args->fh); | 35 | inode = nfs_delegation_find_inode(clp, &args->fh); |
| 30 | if (inode == NULL) | 36 | if (inode == NULL) |
| 31 | goto out_putclient; | 37 | goto out_putclient; |
| @@ -65,23 +71,32 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy) | |||
| 65 | clp = nfs_find_client(args->addr, 4); | 71 | clp = nfs_find_client(args->addr, 4); |
| 66 | if (clp == NULL) | 72 | if (clp == NULL) |
| 67 | goto out; | 73 | goto out; |
| 68 | inode = nfs_delegation_find_inode(clp, &args->fh); | 74 | |
| 69 | if (inode == NULL) | 75 | dprintk("NFS: RECALL callback request from %s\n", |
| 70 | goto out_putclient; | 76 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR)); |
| 71 | /* Set up a helper thread to actually return the delegation */ | 77 | |
| 72 | switch(nfs_async_inode_return_delegation(inode, &args->stateid)) { | 78 | do { |
| 73 | case 0: | 79 | struct nfs_client *prev = clp; |
| 74 | res = 0; | 80 | |
| 75 | break; | 81 | inode = nfs_delegation_find_inode(clp, &args->fh); |
| 76 | case -ENOENT: | 82 | if (inode != NULL) { |
| 77 | res = htonl(NFS4ERR_BAD_STATEID); | 83 | /* Set up a helper thread to actually return the delegation */ |
| 78 | break; | 84 | switch(nfs_async_inode_return_delegation(inode, &args->stateid)) { |
| 79 | default: | 85 | case 0: |
| 80 | res = htonl(NFS4ERR_RESOURCE); | 86 | res = 0; |
| 81 | } | 87 | break; |
| 82 | iput(inode); | 88 | case -ENOENT: |
| 83 | out_putclient: | 89 | if (res != 0) |
| 84 | nfs_put_client(clp); | 90 | res = htonl(NFS4ERR_BAD_STATEID); |
| 91 | break; | ||
| 92 | default: | ||
| 93 | res = htonl(NFS4ERR_RESOURCE); | ||
| 94 | } | ||
| 95 | iput(inode); | ||
| 96 | } | ||
| 97 | clp = nfs_find_client_next(prev); | ||
| 98 | nfs_put_client(prev); | ||
| 99 | } while (clp != NULL); | ||
| 85 | out: | 100 | out: |
| 86 | dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res)); | 101 | dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res)); |
| 87 | return res; | 102 | return res; |
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index 058ade7efe79..c63eb720b68b 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c | |||
| @@ -139,7 +139,7 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound | |||
| 139 | if (unlikely(status != 0)) | 139 | if (unlikely(status != 0)) |
| 140 | return status; | 140 | return status; |
| 141 | /* We do not like overly long tags! */ | 141 | /* We do not like overly long tags! */ |
| 142 | if (hdr->taglen > CB_OP_TAGLEN_MAXSZ-12 || hdr->taglen < 0) { | 142 | if (hdr->taglen > CB_OP_TAGLEN_MAXSZ - 12) { |
| 143 | printk("NFSv4 CALLBACK %s: client sent tag of length %u\n", | 143 | printk("NFSv4 CALLBACK %s: client sent tag of length %u\n", |
| 144 | __FUNCTION__, hdr->taglen); | 144 | __FUNCTION__, hdr->taglen); |
| 145 | return htonl(NFS4ERR_RESOURCE); | 145 | return htonl(NFS4ERR_RESOURCE); |
| @@ -176,7 +176,7 @@ static __be32 decode_getattr_args(struct svc_rqst *rqstp, struct xdr_stream *xdr | |||
| 176 | status = decode_fh(xdr, &args->fh); | 176 | status = decode_fh(xdr, &args->fh); |
| 177 | if (unlikely(status != 0)) | 177 | if (unlikely(status != 0)) |
| 178 | goto out; | 178 | goto out; |
| 179 | args->addr = svc_addr_in(rqstp); | 179 | args->addr = svc_addr(rqstp); |
| 180 | status = decode_bitmap(xdr, args->bitmap); | 180 | status = decode_bitmap(xdr, args->bitmap); |
| 181 | out: | 181 | out: |
| 182 | dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(status)); | 182 | dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(status)); |
| @@ -188,7 +188,7 @@ static __be32 decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, | |||
| 188 | __be32 *p; | 188 | __be32 *p; |
| 189 | __be32 status; | 189 | __be32 status; |
| 190 | 190 | ||
| 191 | args->addr = svc_addr_in(rqstp); | 191 | args->addr = svc_addr(rqstp); |
| 192 | status = decode_stateid(xdr, &args->stateid); | 192 | status = decode_stateid(xdr, &args->stateid); |
| 193 | if (unlikely(status != 0)) | 193 | if (unlikely(status != 0)) |
| 194 | goto out; | 194 | goto out; |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index a6f625497612..685c43f810c1 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
| @@ -34,6 +34,8 @@ | |||
| 34 | #include <linux/nfs_idmap.h> | 34 | #include <linux/nfs_idmap.h> |
| 35 | #include <linux/vfs.h> | 35 | #include <linux/vfs.h> |
| 36 | #include <linux/inet.h> | 36 | #include <linux/inet.h> |
| 37 | #include <linux/in6.h> | ||
| 38 | #include <net/ipv6.h> | ||
| 37 | #include <linux/nfs_xdr.h> | 39 | #include <linux/nfs_xdr.h> |
| 38 | 40 | ||
| 39 | #include <asm/system.h> | 41 | #include <asm/system.h> |
| @@ -93,22 +95,30 @@ struct rpc_program nfsacl_program = { | |||
| 93 | }; | 95 | }; |
| 94 | #endif /* CONFIG_NFS_V3_ACL */ | 96 | #endif /* CONFIG_NFS_V3_ACL */ |
| 95 | 97 | ||
| 98 | struct nfs_client_initdata { | ||
| 99 | const char *hostname; | ||
| 100 | const struct sockaddr *addr; | ||
| 101 | size_t addrlen; | ||
| 102 | const struct nfs_rpc_ops *rpc_ops; | ||
| 103 | int proto; | ||
| 104 | }; | ||
| 105 | |||
| 96 | /* | 106 | /* |
| 97 | * Allocate a shared client record | 107 | * Allocate a shared client record |
| 98 | * | 108 | * |
| 99 | * Since these are allocated/deallocated very rarely, we don't | 109 | * Since these are allocated/deallocated very rarely, we don't |
| 100 | * bother putting them in a slab cache... | 110 | * bother putting them in a slab cache... |
| 101 | */ | 111 | */ |
| 102 | static struct nfs_client *nfs_alloc_client(const char *hostname, | 112 | static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init) |
| 103 | const struct sockaddr_in *addr, | ||
| 104 | int nfsversion) | ||
| 105 | { | 113 | { |
| 106 | struct nfs_client *clp; | 114 | struct nfs_client *clp; |
| 107 | 115 | ||
| 108 | if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) | 116 | if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) |
| 109 | goto error_0; | 117 | goto error_0; |
| 110 | 118 | ||
| 111 | if (nfsversion == 4) { | 119 | clp->rpc_ops = cl_init->rpc_ops; |
| 120 | |||
| 121 | if (cl_init->rpc_ops->version == 4) { | ||
| 112 | if (nfs_callback_up() < 0) | 122 | if (nfs_callback_up() < 0) |
| 113 | goto error_2; | 123 | goto error_2; |
| 114 | __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state); | 124 | __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state); |
| @@ -117,11 +127,11 @@ static struct nfs_client *nfs_alloc_client(const char *hostname, | |||
| 117 | atomic_set(&clp->cl_count, 1); | 127 | atomic_set(&clp->cl_count, 1); |
| 118 | clp->cl_cons_state = NFS_CS_INITING; | 128 | clp->cl_cons_state = NFS_CS_INITING; |
| 119 | 129 | ||
| 120 | clp->cl_nfsversion = nfsversion; | 130 | memcpy(&clp->cl_addr, cl_init->addr, cl_init->addrlen); |
| 121 | memcpy(&clp->cl_addr, addr, sizeof(clp->cl_addr)); | 131 | clp->cl_addrlen = cl_init->addrlen; |
| 122 | 132 | ||
| 123 | if (hostname) { | 133 | if (cl_init->hostname) { |
| 124 | clp->cl_hostname = kstrdup(hostname, GFP_KERNEL); | 134 | clp->cl_hostname = kstrdup(cl_init->hostname, GFP_KERNEL); |
| 125 | if (!clp->cl_hostname) | 135 | if (!clp->cl_hostname) |
| 126 | goto error_3; | 136 | goto error_3; |
| 127 | } | 137 | } |
| @@ -129,6 +139,8 @@ static struct nfs_client *nfs_alloc_client(const char *hostname, | |||
| 129 | INIT_LIST_HEAD(&clp->cl_superblocks); | 139 | INIT_LIST_HEAD(&clp->cl_superblocks); |
| 130 | clp->cl_rpcclient = ERR_PTR(-EINVAL); | 140 | clp->cl_rpcclient = ERR_PTR(-EINVAL); |
| 131 | 141 | ||
| 142 | clp->cl_proto = cl_init->proto; | ||
| 143 | |||
| 132 | #ifdef CONFIG_NFS_V4 | 144 | #ifdef CONFIG_NFS_V4 |
| 133 | init_rwsem(&clp->cl_sem); | 145 | init_rwsem(&clp->cl_sem); |
| 134 | INIT_LIST_HEAD(&clp->cl_delegations); | 146 | INIT_LIST_HEAD(&clp->cl_delegations); |
| @@ -166,7 +178,7 @@ static void nfs4_shutdown_client(struct nfs_client *clp) | |||
| 166 | */ | 178 | */ |
| 167 | static void nfs_free_client(struct nfs_client *clp) | 179 | static void nfs_free_client(struct nfs_client *clp) |
| 168 | { | 180 | { |
| 169 | dprintk("--> nfs_free_client(%d)\n", clp->cl_nfsversion); | 181 | dprintk("--> nfs_free_client(%u)\n", clp->rpc_ops->version); |
| 170 | 182 | ||
| 171 | nfs4_shutdown_client(clp); | 183 | nfs4_shutdown_client(clp); |
| 172 | 184 | ||
| @@ -203,76 +215,148 @@ void nfs_put_client(struct nfs_client *clp) | |||
| 203 | } | 215 | } |
| 204 | } | 216 | } |
| 205 | 217 | ||
| 218 | static int nfs_sockaddr_match_ipaddr4(const struct sockaddr_in *sa1, | ||
| 219 | const struct sockaddr_in *sa2) | ||
| 220 | { | ||
| 221 | return sa1->sin_addr.s_addr == sa2->sin_addr.s_addr; | ||
| 222 | } | ||
| 223 | |||
| 224 | static int nfs_sockaddr_match_ipaddr6(const struct sockaddr_in6 *sa1, | ||
| 225 | const struct sockaddr_in6 *sa2) | ||
| 226 | { | ||
| 227 | return ipv6_addr_equal(&sa1->sin6_addr, &sa2->sin6_addr); | ||
| 228 | } | ||
| 229 | |||
| 230 | static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, | ||
| 231 | const struct sockaddr *sa2) | ||
| 232 | { | ||
| 233 | switch (sa1->sa_family) { | ||
| 234 | case AF_INET: | ||
| 235 | return nfs_sockaddr_match_ipaddr4((const struct sockaddr_in *)sa1, | ||
| 236 | (const struct sockaddr_in *)sa2); | ||
| 237 | case AF_INET6: | ||
| 238 | return nfs_sockaddr_match_ipaddr6((const struct sockaddr_in6 *)sa1, | ||
| 239 | (const struct sockaddr_in6 *)sa2); | ||
| 240 | } | ||
| 241 | BUG(); | ||
| 242 | } | ||
| 243 | |||
| 206 | /* | 244 | /* |
| 207 | * Find a client by address | 245 | * Find a client by IP address and protocol version |
| 208 | * - caller must hold nfs_client_lock | 246 | * - returns NULL if no such client |
| 209 | */ | 247 | */ |
| 210 | static struct nfs_client *__nfs_find_client(const struct sockaddr_in *addr, int nfsversion, int match_port) | 248 | struct nfs_client *nfs_find_client(const struct sockaddr *addr, u32 nfsversion) |
| 211 | { | 249 | { |
| 212 | struct nfs_client *clp; | 250 | struct nfs_client *clp; |
| 213 | 251 | ||
| 252 | spin_lock(&nfs_client_lock); | ||
| 214 | list_for_each_entry(clp, &nfs_client_list, cl_share_link) { | 253 | list_for_each_entry(clp, &nfs_client_list, cl_share_link) { |
| 254 | struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; | ||
| 255 | |||
| 215 | /* Don't match clients that failed to initialise properly */ | 256 | /* Don't match clients that failed to initialise properly */ |
| 216 | if (clp->cl_cons_state < 0) | 257 | if (clp->cl_cons_state != NFS_CS_READY) |
| 217 | continue; | 258 | continue; |
| 218 | 259 | ||
| 219 | /* Different NFS versions cannot share the same nfs_client */ | 260 | /* Different NFS versions cannot share the same nfs_client */ |
| 220 | if (clp->cl_nfsversion != nfsversion) | 261 | if (clp->rpc_ops->version != nfsversion) |
| 221 | continue; | 262 | continue; |
| 222 | 263 | ||
| 223 | if (memcmp(&clp->cl_addr.sin_addr, &addr->sin_addr, | 264 | if (addr->sa_family != clap->sa_family) |
| 224 | sizeof(clp->cl_addr.sin_addr)) != 0) | 265 | continue; |
| 266 | /* Match only the IP address, not the port number */ | ||
| 267 | if (!nfs_sockaddr_match_ipaddr(addr, clap)) | ||
| 225 | continue; | 268 | continue; |
| 226 | 269 | ||
| 227 | if (!match_port || clp->cl_addr.sin_port == addr->sin_port) | 270 | atomic_inc(&clp->cl_count); |
| 228 | goto found; | 271 | spin_unlock(&nfs_client_lock); |
| 272 | return clp; | ||
| 229 | } | 273 | } |
| 230 | 274 | spin_unlock(&nfs_client_lock); | |
| 231 | return NULL; | 275 | return NULL; |
| 232 | |||
| 233 | found: | ||
| 234 | atomic_inc(&clp->cl_count); | ||
| 235 | return clp; | ||
| 236 | } | 276 | } |
| 237 | 277 | ||
| 238 | /* | 278 | /* |
| 239 | * Find a client by IP address and protocol version | 279 | * Find a client by IP address and protocol version |
| 240 | * - returns NULL if no such client | 280 | * - returns NULL if no such client |
| 241 | */ | 281 | */ |
| 242 | struct nfs_client *nfs_find_client(const struct sockaddr_in *addr, int nfsversion) | 282 | struct nfs_client *nfs_find_client_next(struct nfs_client *clp) |
| 243 | { | 283 | { |
| 244 | struct nfs_client *clp; | 284 | struct sockaddr *sap = (struct sockaddr *)&clp->cl_addr; |
| 285 | u32 nfsvers = clp->rpc_ops->version; | ||
| 245 | 286 | ||
| 246 | spin_lock(&nfs_client_lock); | 287 | spin_lock(&nfs_client_lock); |
| 247 | clp = __nfs_find_client(addr, nfsversion, 0); | 288 | list_for_each_entry_continue(clp, &nfs_client_list, cl_share_link) { |
| 289 | struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; | ||
| 290 | |||
| 291 | /* Don't match clients that failed to initialise properly */ | ||
| 292 | if (clp->cl_cons_state != NFS_CS_READY) | ||
| 293 | continue; | ||
| 294 | |||
| 295 | /* Different NFS versions cannot share the same nfs_client */ | ||
| 296 | if (clp->rpc_ops->version != nfsvers) | ||
| 297 | continue; | ||
| 298 | |||
| 299 | if (sap->sa_family != clap->sa_family) | ||
| 300 | continue; | ||
| 301 | /* Match only the IP address, not the port number */ | ||
| 302 | if (!nfs_sockaddr_match_ipaddr(sap, clap)) | ||
| 303 | continue; | ||
| 304 | |||
| 305 | atomic_inc(&clp->cl_count); | ||
| 306 | spin_unlock(&nfs_client_lock); | ||
| 307 | return clp; | ||
| 308 | } | ||
| 248 | spin_unlock(&nfs_client_lock); | 309 | spin_unlock(&nfs_client_lock); |
| 249 | if (clp != NULL && clp->cl_cons_state != NFS_CS_READY) { | 310 | return NULL; |
| 250 | nfs_put_client(clp); | 311 | } |
| 251 | clp = NULL; | 312 | |
| 313 | /* | ||
| 314 | * Find an nfs_client on the list that matches the initialisation data | ||
| 315 | * that is supplied. | ||
| 316 | */ | ||
| 317 | static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *data) | ||
| 318 | { | ||
| 319 | struct nfs_client *clp; | ||
| 320 | |||
| 321 | list_for_each_entry(clp, &nfs_client_list, cl_share_link) { | ||
| 322 | /* Don't match clients that failed to initialise properly */ | ||
| 323 | if (clp->cl_cons_state < 0) | ||
| 324 | continue; | ||
| 325 | |||
| 326 | /* Different NFS versions cannot share the same nfs_client */ | ||
| 327 | if (clp->rpc_ops != data->rpc_ops) | ||
| 328 | continue; | ||
| 329 | |||
| 330 | if (clp->cl_proto != data->proto) | ||
| 331 | continue; | ||
| 332 | |||
| 333 | /* Match the full socket address */ | ||
| 334 | if (memcmp(&clp->cl_addr, data->addr, sizeof(clp->cl_addr)) != 0) | ||
| 335 | continue; | ||
| 336 | |||
| 337 | atomic_inc(&clp->cl_count); | ||
| 338 | return clp; | ||
| 252 | } | 339 | } |
| 253 | return clp; | 340 | return NULL; |
| 254 | } | 341 | } |
| 255 | 342 | ||
| 256 | /* | 343 | /* |
| 257 | * Look up a client by IP address and protocol version | 344 | * Look up a client by IP address and protocol version |
| 258 | * - creates a new record if one doesn't yet exist | 345 | * - creates a new record if one doesn't yet exist |
| 259 | */ | 346 | */ |
| 260 | static struct nfs_client *nfs_get_client(const char *hostname, | 347 | static struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_init) |
| 261 | const struct sockaddr_in *addr, | ||
| 262 | int nfsversion) | ||
| 263 | { | 348 | { |
| 264 | struct nfs_client *clp, *new = NULL; | 349 | struct nfs_client *clp, *new = NULL; |
| 265 | int error; | 350 | int error; |
| 266 | 351 | ||
| 267 | dprintk("--> nfs_get_client(%s,"NIPQUAD_FMT":%d,%d)\n", | 352 | dprintk("--> nfs_get_client(%s,v%u)\n", |
| 268 | hostname ?: "", NIPQUAD(addr->sin_addr), | 353 | cl_init->hostname ?: "", cl_init->rpc_ops->version); |
| 269 | addr->sin_port, nfsversion); | ||
| 270 | 354 | ||
| 271 | /* see if the client already exists */ | 355 | /* see if the client already exists */ |
| 272 | do { | 356 | do { |
| 273 | spin_lock(&nfs_client_lock); | 357 | spin_lock(&nfs_client_lock); |
| 274 | 358 | ||
| 275 | clp = __nfs_find_client(addr, nfsversion, 1); | 359 | clp = nfs_match_client(cl_init); |
| 276 | if (clp) | 360 | if (clp) |
| 277 | goto found_client; | 361 | goto found_client; |
| 278 | if (new) | 362 | if (new) |
| @@ -280,7 +364,7 @@ static struct nfs_client *nfs_get_client(const char *hostname, | |||
| 280 | 364 | ||
| 281 | spin_unlock(&nfs_client_lock); | 365 | spin_unlock(&nfs_client_lock); |
| 282 | 366 | ||
| 283 | new = nfs_alloc_client(hostname, addr, nfsversion); | 367 | new = nfs_alloc_client(cl_init); |
| 284 | } while (new); | 368 | } while (new); |
| 285 | 369 | ||
| 286 | return ERR_PTR(-ENOMEM); | 370 | return ERR_PTR(-ENOMEM); |
| @@ -344,12 +428,16 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, | |||
| 344 | switch (proto) { | 428 | switch (proto) { |
| 345 | case XPRT_TRANSPORT_TCP: | 429 | case XPRT_TRANSPORT_TCP: |
| 346 | case XPRT_TRANSPORT_RDMA: | 430 | case XPRT_TRANSPORT_RDMA: |
| 347 | if (!to->to_initval) | 431 | if (to->to_initval == 0) |
| 348 | to->to_initval = 60 * HZ; | 432 | to->to_initval = 60 * HZ; |
| 349 | if (to->to_initval > NFS_MAX_TCP_TIMEOUT) | 433 | if (to->to_initval > NFS_MAX_TCP_TIMEOUT) |
| 350 | to->to_initval = NFS_MAX_TCP_TIMEOUT; | 434 | to->to_initval = NFS_MAX_TCP_TIMEOUT; |
| 351 | to->to_increment = to->to_initval; | 435 | to->to_increment = to->to_initval; |
| 352 | to->to_maxval = to->to_initval + (to->to_increment * to->to_retries); | 436 | to->to_maxval = to->to_initval + (to->to_increment * to->to_retries); |
| 437 | if (to->to_maxval > NFS_MAX_TCP_TIMEOUT) | ||
| 438 | to->to_maxval = NFS_MAX_TCP_TIMEOUT; | ||
| 439 | if (to->to_maxval < to->to_initval) | ||
| 440 | to->to_maxval = to->to_initval; | ||
| 353 | to->to_exponential = 0; | 441 | to->to_exponential = 0; |
| 354 | break; | 442 | break; |
| 355 | case XPRT_TRANSPORT_UDP: | 443 | case XPRT_TRANSPORT_UDP: |
| @@ -367,19 +455,17 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, | |||
| 367 | /* | 455 | /* |
| 368 | * Create an RPC client handle | 456 | * Create an RPC client handle |
| 369 | */ | 457 | */ |
| 370 | static int nfs_create_rpc_client(struct nfs_client *clp, int proto, | 458 | static int nfs_create_rpc_client(struct nfs_client *clp, |
| 371 | unsigned int timeo, | 459 | const struct rpc_timeout *timeparms, |
| 372 | unsigned int retrans, | 460 | rpc_authflavor_t flavor, |
| 373 | rpc_authflavor_t flavor, | 461 | int flags) |
| 374 | int flags) | ||
| 375 | { | 462 | { |
| 376 | struct rpc_timeout timeparms; | ||
| 377 | struct rpc_clnt *clnt = NULL; | 463 | struct rpc_clnt *clnt = NULL; |
| 378 | struct rpc_create_args args = { | 464 | struct rpc_create_args args = { |
| 379 | .protocol = proto, | 465 | .protocol = clp->cl_proto, |
| 380 | .address = (struct sockaddr *)&clp->cl_addr, | 466 | .address = (struct sockaddr *)&clp->cl_addr, |
| 381 | .addrsize = sizeof(clp->cl_addr), | 467 | .addrsize = clp->cl_addrlen, |
| 382 | .timeout = &timeparms, | 468 | .timeout = timeparms, |
| 383 | .servername = clp->cl_hostname, | 469 | .servername = clp->cl_hostname, |
| 384 | .program = &nfs_program, | 470 | .program = &nfs_program, |
| 385 | .version = clp->rpc_ops->version, | 471 | .version = clp->rpc_ops->version, |
| @@ -390,10 +476,6 @@ static int nfs_create_rpc_client(struct nfs_client *clp, int proto, | |||
| 390 | if (!IS_ERR(clp->cl_rpcclient)) | 476 | if (!IS_ERR(clp->cl_rpcclient)) |
| 391 | return 0; | 477 | return 0; |
| 392 | 478 | ||
| 393 | nfs_init_timeout_values(&timeparms, proto, timeo, retrans); | ||
| 394 | clp->retrans_timeo = timeparms.to_initval; | ||
| 395 | clp->retrans_count = timeparms.to_retries; | ||
| 396 | |||
| 397 | clnt = rpc_create(&args); | 479 | clnt = rpc_create(&args); |
| 398 | if (IS_ERR(clnt)) { | 480 | if (IS_ERR(clnt)) { |
| 399 | dprintk("%s: cannot create RPC client. Error = %ld\n", | 481 | dprintk("%s: cannot create RPC client. Error = %ld\n", |
| @@ -411,7 +493,7 @@ static int nfs_create_rpc_client(struct nfs_client *clp, int proto, | |||
| 411 | static void nfs_destroy_server(struct nfs_server *server) | 493 | static void nfs_destroy_server(struct nfs_server *server) |
| 412 | { | 494 | { |
| 413 | if (!(server->flags & NFS_MOUNT_NONLM)) | 495 | if (!(server->flags & NFS_MOUNT_NONLM)) |
| 414 | lockd_down(); /* release rpc.lockd */ | 496 | nlmclnt_done(server->nlm_host); |
| 415 | } | 497 | } |
| 416 | 498 | ||
| 417 | /* | 499 | /* |
| @@ -419,20 +501,29 @@ static void nfs_destroy_server(struct nfs_server *server) | |||
| 419 | */ | 501 | */ |
| 420 | static int nfs_start_lockd(struct nfs_server *server) | 502 | static int nfs_start_lockd(struct nfs_server *server) |
| 421 | { | 503 | { |
| 422 | int error = 0; | 504 | struct nlm_host *host; |
| 505 | struct nfs_client *clp = server->nfs_client; | ||
| 506 | struct nlmclnt_initdata nlm_init = { | ||
| 507 | .hostname = clp->cl_hostname, | ||
| 508 | .address = (struct sockaddr *)&clp->cl_addr, | ||
| 509 | .addrlen = clp->cl_addrlen, | ||
| 510 | .protocol = server->flags & NFS_MOUNT_TCP ? | ||
| 511 | IPPROTO_TCP : IPPROTO_UDP, | ||
| 512 | .nfs_version = clp->rpc_ops->version, | ||
| 513 | }; | ||
| 423 | 514 | ||
| 424 | if (server->nfs_client->cl_nfsversion > 3) | 515 | if (nlm_init.nfs_version > 3) |
| 425 | goto out; | 516 | return 0; |
| 426 | if (server->flags & NFS_MOUNT_NONLM) | 517 | if (server->flags & NFS_MOUNT_NONLM) |
| 427 | goto out; | 518 | return 0; |
| 428 | error = lockd_up((server->flags & NFS_MOUNT_TCP) ? | 519 | |
| 429 | IPPROTO_TCP : IPPROTO_UDP); | 520 | host = nlmclnt_init(&nlm_init); |
| 430 | if (error < 0) | 521 | if (IS_ERR(host)) |
| 431 | server->flags |= NFS_MOUNT_NONLM; | 522 | return PTR_ERR(host); |
| 432 | else | 523 | |
| 433 | server->destroy = nfs_destroy_server; | 524 | server->nlm_host = host; |
| 434 | out: | 525 | server->destroy = nfs_destroy_server; |
| 435 | return error; | 526 | return 0; |
| 436 | } | 527 | } |
| 437 | 528 | ||
| 438 | /* | 529 | /* |
| @@ -441,7 +532,7 @@ out: | |||
| 441 | #ifdef CONFIG_NFS_V3_ACL | 532 | #ifdef CONFIG_NFS_V3_ACL |
| 442 | static void nfs_init_server_aclclient(struct nfs_server *server) | 533 | static void nfs_init_server_aclclient(struct nfs_server *server) |
| 443 | { | 534 | { |
| 444 | if (server->nfs_client->cl_nfsversion != 3) | 535 | if (server->nfs_client->rpc_ops->version != 3) |
| 445 | goto out_noacl; | 536 | goto out_noacl; |
| 446 | if (server->flags & NFS_MOUNT_NOACL) | 537 | if (server->flags & NFS_MOUNT_NOACL) |
| 447 | goto out_noacl; | 538 | goto out_noacl; |
| @@ -468,7 +559,9 @@ static inline void nfs_init_server_aclclient(struct nfs_server *server) | |||
| 468 | /* | 559 | /* |
| 469 | * Create a general RPC client | 560 | * Create a general RPC client |
| 470 | */ | 561 | */ |
| 471 | static int nfs_init_server_rpcclient(struct nfs_server *server, rpc_authflavor_t pseudoflavour) | 562 | static int nfs_init_server_rpcclient(struct nfs_server *server, |
| 563 | const struct rpc_timeout *timeo, | ||
| 564 | rpc_authflavor_t pseudoflavour) | ||
| 472 | { | 565 | { |
| 473 | struct nfs_client *clp = server->nfs_client; | 566 | struct nfs_client *clp = server->nfs_client; |
| 474 | 567 | ||
| @@ -478,6 +571,11 @@ static int nfs_init_server_rpcclient(struct nfs_server *server, rpc_authflavor_t | |||
| 478 | return PTR_ERR(server->client); | 571 | return PTR_ERR(server->client); |
| 479 | } | 572 | } |
| 480 | 573 | ||
| 574 | memcpy(&server->client->cl_timeout_default, | ||
| 575 | timeo, | ||
| 576 | sizeof(server->client->cl_timeout_default)); | ||
| 577 | server->client->cl_timeout = &server->client->cl_timeout_default; | ||
| 578 | |||
| 481 | if (pseudoflavour != clp->cl_rpcclient->cl_auth->au_flavor) { | 579 | if (pseudoflavour != clp->cl_rpcclient->cl_auth->au_flavor) { |
| 482 | struct rpc_auth *auth; | 580 | struct rpc_auth *auth; |
| 483 | 581 | ||
| @@ -502,6 +600,7 @@ static int nfs_init_server_rpcclient(struct nfs_server *server, rpc_authflavor_t | |||
| 502 | * Initialise an NFS2 or NFS3 client | 600 | * Initialise an NFS2 or NFS3 client |
| 503 | */ | 601 | */ |
| 504 | static int nfs_init_client(struct nfs_client *clp, | 602 | static int nfs_init_client(struct nfs_client *clp, |
| 603 | const struct rpc_timeout *timeparms, | ||
| 505 | const struct nfs_parsed_mount_data *data) | 604 | const struct nfs_parsed_mount_data *data) |
| 506 | { | 605 | { |
| 507 | int error; | 606 | int error; |
| @@ -512,18 +611,11 @@ static int nfs_init_client(struct nfs_client *clp, | |||
| 512 | return 0; | 611 | return 0; |
| 513 | } | 612 | } |
| 514 | 613 | ||
| 515 | /* Check NFS protocol revision and initialize RPC op vector */ | ||
| 516 | clp->rpc_ops = &nfs_v2_clientops; | ||
| 517 | #ifdef CONFIG_NFS_V3 | ||
| 518 | if (clp->cl_nfsversion == 3) | ||
| 519 | clp->rpc_ops = &nfs_v3_clientops; | ||
| 520 | #endif | ||
| 521 | /* | 614 | /* |
| 522 | * Create a client RPC handle for doing FSSTAT with UNIX auth only | 615 | * Create a client RPC handle for doing FSSTAT with UNIX auth only |
| 523 | * - RFC 2623, sec 2.3.2 | 616 | * - RFC 2623, sec 2.3.2 |
| 524 | */ | 617 | */ |
| 525 | error = nfs_create_rpc_client(clp, data->nfs_server.protocol, | 618 | error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX, 0); |
| 526 | data->timeo, data->retrans, RPC_AUTH_UNIX, 0); | ||
| 527 | if (error < 0) | 619 | if (error < 0) |
| 528 | goto error; | 620 | goto error; |
| 529 | nfs_mark_client_ready(clp, NFS_CS_READY); | 621 | nfs_mark_client_ready(clp, NFS_CS_READY); |
| @@ -541,25 +633,34 @@ error: | |||
| 541 | static int nfs_init_server(struct nfs_server *server, | 633 | static int nfs_init_server(struct nfs_server *server, |
| 542 | const struct nfs_parsed_mount_data *data) | 634 | const struct nfs_parsed_mount_data *data) |
| 543 | { | 635 | { |
| 636 | struct nfs_client_initdata cl_init = { | ||
| 637 | .hostname = data->nfs_server.hostname, | ||
| 638 | .addr = (const struct sockaddr *)&data->nfs_server.address, | ||
| 639 | .addrlen = data->nfs_server.addrlen, | ||
| 640 | .rpc_ops = &nfs_v2_clientops, | ||
| 641 | .proto = data->nfs_server.protocol, | ||
| 642 | }; | ||
| 643 | struct rpc_timeout timeparms; | ||
| 544 | struct nfs_client *clp; | 644 | struct nfs_client *clp; |
| 545 | int error, nfsvers = 2; | 645 | int error; |
| 546 | 646 | ||
| 547 | dprintk("--> nfs_init_server()\n"); | 647 | dprintk("--> nfs_init_server()\n"); |
| 548 | 648 | ||
| 549 | #ifdef CONFIG_NFS_V3 | 649 | #ifdef CONFIG_NFS_V3 |
| 550 | if (data->flags & NFS_MOUNT_VER3) | 650 | if (data->flags & NFS_MOUNT_VER3) |
| 551 | nfsvers = 3; | 651 | cl_init.rpc_ops = &nfs_v3_clientops; |
| 552 | #endif | 652 | #endif |
| 553 | 653 | ||
| 554 | /* Allocate or find a client reference we can use */ | 654 | /* Allocate or find a client reference we can use */ |
| 555 | clp = nfs_get_client(data->nfs_server.hostname, | 655 | clp = nfs_get_client(&cl_init); |
| 556 | &data->nfs_server.address, nfsvers); | ||
| 557 | if (IS_ERR(clp)) { | 656 | if (IS_ERR(clp)) { |
| 558 | dprintk("<-- nfs_init_server() = error %ld\n", PTR_ERR(clp)); | 657 | dprintk("<-- nfs_init_server() = error %ld\n", PTR_ERR(clp)); |
| 559 | return PTR_ERR(clp); | 658 | return PTR_ERR(clp); |
| 560 | } | 659 | } |
| 561 | 660 | ||
| 562 | error = nfs_init_client(clp, data); | 661 | nfs_init_timeout_values(&timeparms, data->nfs_server.protocol, |
| 662 | data->timeo, data->retrans); | ||
| 663 | error = nfs_init_client(clp, &timeparms, data); | ||
| 563 | if (error < 0) | 664 | if (error < 0) |
| 564 | goto error; | 665 | goto error; |
| 565 | 666 | ||
| @@ -583,7 +684,7 @@ static int nfs_init_server(struct nfs_server *server, | |||
| 583 | if (error < 0) | 684 | if (error < 0) |
| 584 | goto error; | 685 | goto error; |
| 585 | 686 | ||
| 586 | error = nfs_init_server_rpcclient(server, data->auth_flavors[0]); | 687 | error = nfs_init_server_rpcclient(server, &timeparms, data->auth_flavors[0]); |
| 587 | if (error < 0) | 688 | if (error < 0) |
| 588 | goto error; | 689 | goto error; |
| 589 | 690 | ||
| @@ -729,6 +830,9 @@ static struct nfs_server *nfs_alloc_server(void) | |||
| 729 | INIT_LIST_HEAD(&server->client_link); | 830 | INIT_LIST_HEAD(&server->client_link); |
| 730 | INIT_LIST_HEAD(&server->master_link); | 831 | INIT_LIST_HEAD(&server->master_link); |
| 731 | 832 | ||
| 833 | init_waitqueue_head(&server->active_wq); | ||
| 834 | atomic_set(&server->active, 0); | ||
| 835 | |||
| 732 | server->io_stats = nfs_alloc_iostats(); | 836 | server->io_stats = nfs_alloc_iostats(); |
| 733 | if (!server->io_stats) { | 837 | if (!server->io_stats) { |
| 734 | kfree(server); | 838 | kfree(server); |
| @@ -840,7 +944,7 @@ error: | |||
| 840 | * Initialise an NFS4 client record | 944 | * Initialise an NFS4 client record |
| 841 | */ | 945 | */ |
| 842 | static int nfs4_init_client(struct nfs_client *clp, | 946 | static int nfs4_init_client(struct nfs_client *clp, |
| 843 | int proto, int timeo, int retrans, | 947 | const struct rpc_timeout *timeparms, |
| 844 | const char *ip_addr, | 948 | const char *ip_addr, |
| 845 | rpc_authflavor_t authflavour) | 949 | rpc_authflavor_t authflavour) |
| 846 | { | 950 | { |
| @@ -855,7 +959,7 @@ static int nfs4_init_client(struct nfs_client *clp, | |||
| 855 | /* Check NFS protocol revision and initialize RPC op vector */ | 959 | /* Check NFS protocol revision and initialize RPC op vector */ |
| 856 | clp->rpc_ops = &nfs_v4_clientops; | 960 | clp->rpc_ops = &nfs_v4_clientops; |
| 857 | 961 | ||
| 858 | error = nfs_create_rpc_client(clp, proto, timeo, retrans, authflavour, | 962 | error = nfs_create_rpc_client(clp, timeparms, authflavour, |
| 859 | RPC_CLNT_CREATE_DISCRTRY); | 963 | RPC_CLNT_CREATE_DISCRTRY); |
| 860 | if (error < 0) | 964 | if (error < 0) |
| 861 | goto error; | 965 | goto error; |
| @@ -882,23 +986,32 @@ error: | |||
| 882 | * Set up an NFS4 client | 986 | * Set up an NFS4 client |
| 883 | */ | 987 | */ |
| 884 | static int nfs4_set_client(struct nfs_server *server, | 988 | static int nfs4_set_client(struct nfs_server *server, |
| 885 | const char *hostname, const struct sockaddr_in *addr, | 989 | const char *hostname, |
| 990 | const struct sockaddr *addr, | ||
| 991 | const size_t addrlen, | ||
| 886 | const char *ip_addr, | 992 | const char *ip_addr, |
| 887 | rpc_authflavor_t authflavour, | 993 | rpc_authflavor_t authflavour, |
| 888 | int proto, int timeo, int retrans) | 994 | int proto, const struct rpc_timeout *timeparms) |
| 889 | { | 995 | { |
| 996 | struct nfs_client_initdata cl_init = { | ||
| 997 | .hostname = hostname, | ||
| 998 | .addr = addr, | ||
| 999 | .addrlen = addrlen, | ||
| 1000 | .rpc_ops = &nfs_v4_clientops, | ||
| 1001 | .proto = proto, | ||
| 1002 | }; | ||
| 890 | struct nfs_client *clp; | 1003 | struct nfs_client *clp; |
| 891 | int error; | 1004 | int error; |
| 892 | 1005 | ||
| 893 | dprintk("--> nfs4_set_client()\n"); | 1006 | dprintk("--> nfs4_set_client()\n"); |
| 894 | 1007 | ||
| 895 | /* Allocate or find a client reference we can use */ | 1008 | /* Allocate or find a client reference we can use */ |
| 896 | clp = nfs_get_client(hostname, addr, 4); | 1009 | clp = nfs_get_client(&cl_init); |
| 897 | if (IS_ERR(clp)) { | 1010 | if (IS_ERR(clp)) { |
| 898 | error = PTR_ERR(clp); | 1011 | error = PTR_ERR(clp); |
| 899 | goto error; | 1012 | goto error; |
| 900 | } | 1013 | } |
| 901 | error = nfs4_init_client(clp, proto, timeo, retrans, ip_addr, authflavour); | 1014 | error = nfs4_init_client(clp, timeparms, ip_addr, authflavour); |
| 902 | if (error < 0) | 1015 | if (error < 0) |
| 903 | goto error_put; | 1016 | goto error_put; |
| 904 | 1017 | ||
| @@ -919,10 +1032,26 @@ error: | |||
| 919 | static int nfs4_init_server(struct nfs_server *server, | 1032 | static int nfs4_init_server(struct nfs_server *server, |
| 920 | const struct nfs_parsed_mount_data *data) | 1033 | const struct nfs_parsed_mount_data *data) |
| 921 | { | 1034 | { |
| 1035 | struct rpc_timeout timeparms; | ||
| 922 | int error; | 1036 | int error; |
| 923 | 1037 | ||
| 924 | dprintk("--> nfs4_init_server()\n"); | 1038 | dprintk("--> nfs4_init_server()\n"); |
| 925 | 1039 | ||
| 1040 | nfs_init_timeout_values(&timeparms, data->nfs_server.protocol, | ||
| 1041 | data->timeo, data->retrans); | ||
| 1042 | |||
| 1043 | /* Get a client record */ | ||
| 1044 | error = nfs4_set_client(server, | ||
| 1045 | data->nfs_server.hostname, | ||
| 1046 | (const struct sockaddr *)&data->nfs_server.address, | ||
| 1047 | data->nfs_server.addrlen, | ||
| 1048 | data->client_address, | ||
| 1049 | data->auth_flavors[0], | ||
| 1050 | data->nfs_server.protocol, | ||
| 1051 | &timeparms); | ||
| 1052 | if (error < 0) | ||
| 1053 | goto error; | ||
| 1054 | |||
| 926 | /* Initialise the client representation from the mount data */ | 1055 | /* Initialise the client representation from the mount data */ |
| 927 | server->flags = data->flags & NFS_MOUNT_FLAGMASK; | 1056 | server->flags = data->flags & NFS_MOUNT_FLAGMASK; |
| 928 | server->caps |= NFS_CAP_ATOMIC_OPEN; | 1057 | server->caps |= NFS_CAP_ATOMIC_OPEN; |
| @@ -937,8 +1066,9 @@ static int nfs4_init_server(struct nfs_server *server, | |||
| 937 | server->acdirmin = data->acdirmin * HZ; | 1066 | server->acdirmin = data->acdirmin * HZ; |
| 938 | server->acdirmax = data->acdirmax * HZ; | 1067 | server->acdirmax = data->acdirmax * HZ; |
| 939 | 1068 | ||
| 940 | error = nfs_init_server_rpcclient(server, data->auth_flavors[0]); | 1069 | error = nfs_init_server_rpcclient(server, &timeparms, data->auth_flavors[0]); |
| 941 | 1070 | ||
| 1071 | error: | ||
| 942 | /* Done */ | 1072 | /* Done */ |
| 943 | dprintk("<-- nfs4_init_server() = %d\n", error); | 1073 | dprintk("<-- nfs4_init_server() = %d\n", error); |
| 944 | return error; | 1074 | return error; |
| @@ -961,17 +1091,6 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, | |||
| 961 | if (!server) | 1091 | if (!server) |
| 962 | return ERR_PTR(-ENOMEM); | 1092 | return ERR_PTR(-ENOMEM); |
| 963 | 1093 | ||
| 964 | /* Get a client record */ | ||
| 965 | error = nfs4_set_client(server, | ||
| 966 | data->nfs_server.hostname, | ||
| 967 | &data->nfs_server.address, | ||
| 968 | data->client_address, | ||
| 969 | data->auth_flavors[0], | ||
| 970 | data->nfs_server.protocol, | ||
| 971 | data->timeo, data->retrans); | ||
| 972 | if (error < 0) | ||
| 973 | goto error; | ||
| 974 | |||
| 975 | /* set up the general RPC client */ | 1094 | /* set up the general RPC client */ |
| 976 | error = nfs4_init_server(server, data); | 1095 | error = nfs4_init_server(server, data); |
| 977 | if (error < 0) | 1096 | if (error < 0) |
| @@ -1039,12 +1158,13 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
| 1039 | 1158 | ||
| 1040 | /* Get a client representation. | 1159 | /* Get a client representation. |
| 1041 | * Note: NFSv4 always uses TCP, */ | 1160 | * Note: NFSv4 always uses TCP, */ |
| 1042 | error = nfs4_set_client(server, data->hostname, data->addr, | 1161 | error = nfs4_set_client(server, data->hostname, |
| 1043 | parent_client->cl_ipaddr, | 1162 | data->addr, |
| 1044 | data->authflavor, | 1163 | data->addrlen, |
| 1045 | parent_server->client->cl_xprt->prot, | 1164 | parent_client->cl_ipaddr, |
| 1046 | parent_client->retrans_timeo, | 1165 | data->authflavor, |
| 1047 | parent_client->retrans_count); | 1166 | parent_server->client->cl_xprt->prot, |
| 1167 | parent_server->client->cl_timeout); | ||
| 1048 | if (error < 0) | 1168 | if (error < 0) |
| 1049 | goto error; | 1169 | goto error; |
| 1050 | 1170 | ||
| @@ -1052,7 +1172,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
| 1052 | nfs_server_copy_userdata(server, parent_server); | 1172 | nfs_server_copy_userdata(server, parent_server); |
| 1053 | server->caps |= NFS_CAP_ATOMIC_OPEN; | 1173 | server->caps |= NFS_CAP_ATOMIC_OPEN; |
| 1054 | 1174 | ||
| 1055 | error = nfs_init_server_rpcclient(server, data->authflavor); | 1175 | error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout, data->authflavor); |
| 1056 | if (error < 0) | 1176 | if (error < 0) |
| 1057 | goto error; | 1177 | goto error; |
| 1058 | 1178 | ||
| @@ -1121,7 +1241,9 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source, | |||
| 1121 | 1241 | ||
| 1122 | server->fsid = fattr->fsid; | 1242 | server->fsid = fattr->fsid; |
| 1123 | 1243 | ||
| 1124 | error = nfs_init_server_rpcclient(server, source->client->cl_auth->au_flavor); | 1244 | error = nfs_init_server_rpcclient(server, |
| 1245 | source->client->cl_timeout, | ||
| 1246 | source->client->cl_auth->au_flavor); | ||
| 1125 | if (error < 0) | 1247 | if (error < 0) |
| 1126 | goto out_free_server; | 1248 | goto out_free_server; |
| 1127 | if (!IS_ERR(source->client_acl)) | 1249 | if (!IS_ERR(source->client_acl)) |
| @@ -1263,10 +1385,10 @@ static int nfs_server_list_show(struct seq_file *m, void *v) | |||
| 1263 | /* display one transport per line on subsequent lines */ | 1385 | /* display one transport per line on subsequent lines */ |
| 1264 | clp = list_entry(v, struct nfs_client, cl_share_link); | 1386 | clp = list_entry(v, struct nfs_client, cl_share_link); |
| 1265 | 1387 | ||
| 1266 | seq_printf(m, "v%d %02x%02x%02x%02x %4hx %3d %s\n", | 1388 | seq_printf(m, "v%u %s %s %3d %s\n", |
| 1267 | clp->cl_nfsversion, | 1389 | clp->rpc_ops->version, |
| 1268 | NIPQUAD(clp->cl_addr.sin_addr), | 1390 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR), |
| 1269 | ntohs(clp->cl_addr.sin_port), | 1391 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT), |
| 1270 | atomic_read(&clp->cl_count), | 1392 | atomic_read(&clp->cl_count), |
| 1271 | clp->cl_hostname); | 1393 | clp->cl_hostname); |
| 1272 | 1394 | ||
| @@ -1342,10 +1464,10 @@ static int nfs_volume_list_show(struct seq_file *m, void *v) | |||
| 1342 | (unsigned long long) server->fsid.major, | 1464 | (unsigned long long) server->fsid.major, |
| 1343 | (unsigned long long) server->fsid.minor); | 1465 | (unsigned long long) server->fsid.minor); |
| 1344 | 1466 | ||
| 1345 | seq_printf(m, "v%d %02x%02x%02x%02x %4hx %-7s %-17s\n", | 1467 | seq_printf(m, "v%u %s %s %-7s %-17s\n", |
| 1346 | clp->cl_nfsversion, | 1468 | clp->rpc_ops->version, |
| 1347 | NIPQUAD(clp->cl_addr.sin_addr), | 1469 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR), |
| 1348 | ntohs(clp->cl_addr.sin_port), | 1470 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT), |
| 1349 | dev, | 1471 | dev, |
| 1350 | fsid); | 1472 | fsid); |
| 1351 | 1473 | ||
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 11833f4caeaa..b9eadd18ba70 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
| @@ -125,6 +125,32 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, st | |||
| 125 | put_rpccred(oldcred); | 125 | put_rpccred(oldcred); |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync) | ||
| 129 | { | ||
| 130 | int res = 0; | ||
| 131 | |||
| 132 | res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid, issync); | ||
| 133 | nfs_free_delegation(delegation); | ||
| 134 | return res; | ||
| 135 | } | ||
| 136 | |||
| 137 | static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid) | ||
| 138 | { | ||
| 139 | struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation); | ||
| 140 | |||
| 141 | if (delegation == NULL) | ||
| 142 | goto nomatch; | ||
| 143 | if (stateid != NULL && memcmp(delegation->stateid.data, stateid->data, | ||
| 144 | sizeof(delegation->stateid.data)) != 0) | ||
| 145 | goto nomatch; | ||
| 146 | list_del_rcu(&delegation->super_list); | ||
| 147 | nfsi->delegation_state = 0; | ||
| 148 | rcu_assign_pointer(nfsi->delegation, NULL); | ||
| 149 | return delegation; | ||
| 150 | nomatch: | ||
| 151 | return NULL; | ||
| 152 | } | ||
| 153 | |||
| 128 | /* | 154 | /* |
| 129 | * Set up a delegation on an inode | 155 | * Set up a delegation on an inode |
| 130 | */ | 156 | */ |
| @@ -133,6 +159,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |||
| 133 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; | 159 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; |
| 134 | struct nfs_inode *nfsi = NFS_I(inode); | 160 | struct nfs_inode *nfsi = NFS_I(inode); |
| 135 | struct nfs_delegation *delegation; | 161 | struct nfs_delegation *delegation; |
| 162 | struct nfs_delegation *freeme = NULL; | ||
| 136 | int status = 0; | 163 | int status = 0; |
| 137 | 164 | ||
| 138 | delegation = kmalloc(sizeof(*delegation), GFP_KERNEL); | 165 | delegation = kmalloc(sizeof(*delegation), GFP_KERNEL); |
| @@ -147,41 +174,45 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |||
| 147 | delegation->inode = inode; | 174 | delegation->inode = inode; |
| 148 | 175 | ||
| 149 | spin_lock(&clp->cl_lock); | 176 | spin_lock(&clp->cl_lock); |
| 150 | if (rcu_dereference(nfsi->delegation) == NULL) { | 177 | if (rcu_dereference(nfsi->delegation) != NULL) { |
| 151 | list_add_rcu(&delegation->super_list, &clp->cl_delegations); | ||
| 152 | nfsi->delegation_state = delegation->type; | ||
| 153 | rcu_assign_pointer(nfsi->delegation, delegation); | ||
| 154 | delegation = NULL; | ||
| 155 | } else { | ||
| 156 | if (memcmp(&delegation->stateid, &nfsi->delegation->stateid, | 178 | if (memcmp(&delegation->stateid, &nfsi->delegation->stateid, |
| 157 | sizeof(delegation->stateid)) != 0 || | 179 | sizeof(delegation->stateid)) == 0 && |
| 158 | delegation->type != nfsi->delegation->type) { | 180 | delegation->type == nfsi->delegation->type) { |
| 159 | printk("%s: server %u.%u.%u.%u, handed out a duplicate delegation!\n", | 181 | goto out; |
| 160 | __FUNCTION__, NIPQUAD(clp->cl_addr.sin_addr)); | 182 | } |
| 161 | status = -EIO; | 183 | /* |
| 184 | * Deal with broken servers that hand out two | ||
| 185 | * delegations for the same file. | ||
| 186 | */ | ||
| 187 | dfprintk(FILE, "%s: server %s handed out " | ||
| 188 | "a duplicate delegation!\n", | ||
| 189 | __FUNCTION__, clp->cl_hostname); | ||
| 190 | if (delegation->type <= nfsi->delegation->type) { | ||
| 191 | freeme = delegation; | ||
| 192 | delegation = NULL; | ||
| 193 | goto out; | ||
| 162 | } | 194 | } |
| 195 | freeme = nfs_detach_delegation_locked(nfsi, NULL); | ||
| 163 | } | 196 | } |
| 197 | list_add_rcu(&delegation->super_list, &clp->cl_delegations); | ||
| 198 | nfsi->delegation_state = delegation->type; | ||
| 199 | rcu_assign_pointer(nfsi->delegation, delegation); | ||
| 200 | delegation = NULL; | ||
| 164 | 201 | ||
| 165 | /* Ensure we revalidate the attributes and page cache! */ | 202 | /* Ensure we revalidate the attributes and page cache! */ |
| 166 | spin_lock(&inode->i_lock); | 203 | spin_lock(&inode->i_lock); |
| 167 | nfsi->cache_validity |= NFS_INO_REVAL_FORCED; | 204 | nfsi->cache_validity |= NFS_INO_REVAL_FORCED; |
| 168 | spin_unlock(&inode->i_lock); | 205 | spin_unlock(&inode->i_lock); |
| 169 | 206 | ||
| 207 | out: | ||
| 170 | spin_unlock(&clp->cl_lock); | 208 | spin_unlock(&clp->cl_lock); |
| 171 | if (delegation != NULL) | 209 | if (delegation != NULL) |
| 172 | nfs_free_delegation(delegation); | 210 | nfs_free_delegation(delegation); |
| 211 | if (freeme != NULL) | ||
| 212 | nfs_do_return_delegation(inode, freeme, 0); | ||
| 173 | return status; | 213 | return status; |
| 174 | } | 214 | } |
| 175 | 215 | ||
| 176 | static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation) | ||
| 177 | { | ||
| 178 | int res = 0; | ||
| 179 | |||
| 180 | res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid); | ||
| 181 | nfs_free_delegation(delegation); | ||
| 182 | return res; | ||
| 183 | } | ||
| 184 | |||
| 185 | /* Sync all data to disk upon delegation return */ | 216 | /* Sync all data to disk upon delegation return */ |
| 186 | static void nfs_msync_inode(struct inode *inode) | 217 | static void nfs_msync_inode(struct inode *inode) |
| 187 | { | 218 | { |
| @@ -207,24 +238,28 @@ static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegat | |||
| 207 | up_read(&clp->cl_sem); | 238 | up_read(&clp->cl_sem); |
| 208 | nfs_msync_inode(inode); | 239 | nfs_msync_inode(inode); |
| 209 | 240 | ||
| 210 | return nfs_do_return_delegation(inode, delegation); | 241 | return nfs_do_return_delegation(inode, delegation, 1); |
| 211 | } | 242 | } |
| 212 | 243 | ||
| 213 | static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid) | 244 | /* |
| 245 | * This function returns the delegation without reclaiming opens | ||
| 246 | * or protecting against delegation reclaims. | ||
| 247 | * It is therefore really only safe to be called from | ||
| 248 | * nfs4_clear_inode() | ||
| 249 | */ | ||
| 250 | void nfs_inode_return_delegation_noreclaim(struct inode *inode) | ||
| 214 | { | 251 | { |
| 215 | struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation); | 252 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; |
| 253 | struct nfs_inode *nfsi = NFS_I(inode); | ||
| 254 | struct nfs_delegation *delegation; | ||
| 216 | 255 | ||
| 217 | if (delegation == NULL) | 256 | if (rcu_dereference(nfsi->delegation) != NULL) { |
| 218 | goto nomatch; | 257 | spin_lock(&clp->cl_lock); |
| 219 | if (stateid != NULL && memcmp(delegation->stateid.data, stateid->data, | 258 | delegation = nfs_detach_delegation_locked(nfsi, NULL); |
| 220 | sizeof(delegation->stateid.data)) != 0) | 259 | spin_unlock(&clp->cl_lock); |
| 221 | goto nomatch; | 260 | if (delegation != NULL) |
| 222 | list_del_rcu(&delegation->super_list); | 261 | nfs_do_return_delegation(inode, delegation, 0); |
| 223 | nfsi->delegation_state = 0; | 262 | } |
| 224 | rcu_assign_pointer(nfsi->delegation, NULL); | ||
| 225 | return delegation; | ||
| 226 | nomatch: | ||
| 227 | return NULL; | ||
| 228 | } | 263 | } |
| 229 | 264 | ||
| 230 | int nfs_inode_return_delegation(struct inode *inode) | 265 | int nfs_inode_return_delegation(struct inode *inode) |
| @@ -314,8 +349,9 @@ void nfs_expire_all_delegations(struct nfs_client *clp) | |||
| 314 | __module_get(THIS_MODULE); | 349 | __module_get(THIS_MODULE); |
| 315 | atomic_inc(&clp->cl_count); | 350 | atomic_inc(&clp->cl_count); |
| 316 | task = kthread_run(nfs_do_expire_all_delegations, clp, | 351 | task = kthread_run(nfs_do_expire_all_delegations, clp, |
| 317 | "%u.%u.%u.%u-delegreturn", | 352 | "%s-delegreturn", |
| 318 | NIPQUAD(clp->cl_addr.sin_addr)); | 353 | rpc_peeraddr2str(clp->cl_rpcclient, |
| 354 | RPC_DISPLAY_ADDR)); | ||
| 319 | if (!IS_ERR(task)) | 355 | if (!IS_ERR(task)) |
| 320 | return; | 356 | return; |
| 321 | nfs_put_client(clp); | 357 | nfs_put_client(clp); |
| @@ -386,7 +422,7 @@ static int recall_thread(void *data) | |||
| 386 | nfs_msync_inode(inode); | 422 | nfs_msync_inode(inode); |
| 387 | 423 | ||
| 388 | if (delegation != NULL) | 424 | if (delegation != NULL) |
| 389 | nfs_do_return_delegation(inode, delegation); | 425 | nfs_do_return_delegation(inode, delegation, 1); |
| 390 | iput(inode); | 426 | iput(inode); |
| 391 | module_put_and_exit(0); | 427 | module_put_and_exit(0); |
| 392 | } | 428 | } |
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index 5874ce7fdbae..f1c5e2a5d88e 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h | |||
| @@ -29,6 +29,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |||
| 29 | void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); | 29 | void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); |
| 30 | int nfs_inode_return_delegation(struct inode *inode); | 30 | int nfs_inode_return_delegation(struct inode *inode); |
| 31 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid); | 31 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid); |
| 32 | void nfs_inode_return_delegation_noreclaim(struct inode *inode); | ||
| 32 | 33 | ||
| 33 | struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); | 34 | struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); |
| 34 | void nfs_return_all_delegations(struct super_block *sb); | 35 | void nfs_return_all_delegations(struct super_block *sb); |
| @@ -39,7 +40,7 @@ void nfs_delegation_mark_reclaim(struct nfs_client *clp); | |||
| 39 | void nfs_delegation_reap_unclaimed(struct nfs_client *clp); | 40 | void nfs_delegation_reap_unclaimed(struct nfs_client *clp); |
| 40 | 41 | ||
| 41 | /* NFSv4 delegation-related procedures */ | 42 | /* NFSv4 delegation-related procedures */ |
| 42 | int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid); | 43 | int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync); |
| 43 | int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid); | 44 | int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid); |
| 44 | int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl); | 45 | int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl); |
| 45 | int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode); | 46 | int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode); |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index f697b5c74b7c..476cb0f837fd 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
| @@ -192,7 +192,7 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page) | |||
| 192 | /* We requested READDIRPLUS, but the server doesn't grok it */ | 192 | /* We requested READDIRPLUS, but the server doesn't grok it */ |
| 193 | if (error == -ENOTSUPP && desc->plus) { | 193 | if (error == -ENOTSUPP && desc->plus) { |
| 194 | NFS_SERVER(inode)->caps &= ~NFS_CAP_READDIRPLUS; | 194 | NFS_SERVER(inode)->caps &= ~NFS_CAP_READDIRPLUS; |
| 195 | clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode)); | 195 | clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags); |
| 196 | desc->plus = 0; | 196 | desc->plus = 0; |
| 197 | goto again; | 197 | goto again; |
| 198 | } | 198 | } |
| @@ -537,12 +537,6 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
| 537 | 537 | ||
| 538 | lock_kernel(); | 538 | lock_kernel(); |
| 539 | 539 | ||
| 540 | res = nfs_revalidate_mapping_nolock(inode, filp->f_mapping); | ||
| 541 | if (res < 0) { | ||
| 542 | unlock_kernel(); | ||
| 543 | return res; | ||
| 544 | } | ||
| 545 | |||
| 546 | /* | 540 | /* |
| 547 | * filp->f_pos points to the dirent entry number. | 541 | * filp->f_pos points to the dirent entry number. |
| 548 | * *desc->dir_cookie has the cookie for the next entry. We have | 542 | * *desc->dir_cookie has the cookie for the next entry. We have |
| @@ -564,6 +558,10 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
| 564 | desc->entry = &my_entry; | 558 | desc->entry = &my_entry; |
| 565 | 559 | ||
| 566 | nfs_block_sillyrename(dentry); | 560 | nfs_block_sillyrename(dentry); |
| 561 | res = nfs_revalidate_mapping_nolock(inode, filp->f_mapping); | ||
| 562 | if (res < 0) | ||
| 563 | goto out; | ||
| 564 | |||
| 567 | while(!desc->entry->eof) { | 565 | while(!desc->entry->eof) { |
| 568 | res = readdir_search_pagecache(desc); | 566 | res = readdir_search_pagecache(desc); |
| 569 | 567 | ||
| @@ -579,7 +577,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
| 579 | break; | 577 | break; |
| 580 | } | 578 | } |
| 581 | if (res == -ETOOSMALL && desc->plus) { | 579 | if (res == -ETOOSMALL && desc->plus) { |
| 582 | clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode)); | 580 | clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags); |
| 583 | nfs_zap_caches(inode); | 581 | nfs_zap_caches(inode); |
| 584 | desc->plus = 0; | 582 | desc->plus = 0; |
| 585 | desc->entry->eof = 0; | 583 | desc->entry->eof = 0; |
| @@ -594,6 +592,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
| 594 | break; | 592 | break; |
| 595 | } | 593 | } |
| 596 | } | 594 | } |
| 595 | out: | ||
| 597 | nfs_unblock_sillyrename(dentry); | 596 | nfs_unblock_sillyrename(dentry); |
| 598 | unlock_kernel(); | 597 | unlock_kernel(); |
| 599 | if (res > 0) | 598 | if (res > 0) |
| @@ -639,6 +638,21 @@ static int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync) | |||
| 639 | return 0; | 638 | return 0; |
| 640 | } | 639 | } |
| 641 | 640 | ||
| 641 | /** | ||
| 642 | * nfs_force_lookup_revalidate - Mark the directory as having changed | ||
| 643 | * @dir - pointer to directory inode | ||
| 644 | * | ||
| 645 | * This forces the revalidation code in nfs_lookup_revalidate() to do a | ||
| 646 | * full lookup on all child dentries of 'dir' whenever a change occurs | ||
| 647 | * on the server that might have invalidated our dcache. | ||
| 648 | * | ||
| 649 | * The caller should be holding dir->i_lock | ||
| 650 | */ | ||
| 651 | void nfs_force_lookup_revalidate(struct inode *dir) | ||
| 652 | { | ||
| 653 | NFS_I(dir)->cache_change_attribute = jiffies; | ||
| 654 | } | ||
| 655 | |||
| 642 | /* | 656 | /* |
| 643 | * A check for whether or not the parent directory has changed. | 657 | * A check for whether or not the parent directory has changed. |
| 644 | * In the case it has, we assume that the dentries are untrustworthy | 658 | * In the case it has, we assume that the dentries are untrustworthy |
| @@ -827,6 +841,10 @@ static int nfs_dentry_delete(struct dentry *dentry) | |||
| 827 | dentry->d_parent->d_name.name, dentry->d_name.name, | 841 | dentry->d_parent->d_name.name, dentry->d_name.name, |
| 828 | dentry->d_flags); | 842 | dentry->d_flags); |
| 829 | 843 | ||
| 844 | /* Unhash any dentry with a stale inode */ | ||
| 845 | if (dentry->d_inode != NULL && NFS_STALE(dentry->d_inode)) | ||
| 846 | return 1; | ||
| 847 | |||
| 830 | if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { | 848 | if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { |
| 831 | /* Unhash it, so that ->d_iput() would be called */ | 849 | /* Unhash it, so that ->d_iput() would be called */ |
| 832 | return 1; | 850 | return 1; |
| @@ -846,7 +864,6 @@ static int nfs_dentry_delete(struct dentry *dentry) | |||
| 846 | */ | 864 | */ |
| 847 | static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode) | 865 | static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode) |
| 848 | { | 866 | { |
| 849 | nfs_inode_return_delegation(inode); | ||
| 850 | if (S_ISDIR(inode->i_mode)) | 867 | if (S_ISDIR(inode->i_mode)) |
| 851 | /* drop any readdir cache as it could easily be old */ | 868 | /* drop any readdir cache as it could easily be old */ |
| 852 | NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA; | 869 | NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA; |
| @@ -1268,6 +1285,12 @@ out_err: | |||
| 1268 | return error; | 1285 | return error; |
| 1269 | } | 1286 | } |
| 1270 | 1287 | ||
| 1288 | static void nfs_dentry_handle_enoent(struct dentry *dentry) | ||
| 1289 | { | ||
| 1290 | if (dentry->d_inode != NULL && !d_unhashed(dentry)) | ||
| 1291 | d_delete(dentry); | ||
| 1292 | } | ||
| 1293 | |||
| 1271 | static int nfs_rmdir(struct inode *dir, struct dentry *dentry) | 1294 | static int nfs_rmdir(struct inode *dir, struct dentry *dentry) |
| 1272 | { | 1295 | { |
| 1273 | int error; | 1296 | int error; |
| @@ -1280,6 +1303,8 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
| 1280 | /* Ensure the VFS deletes this inode */ | 1303 | /* Ensure the VFS deletes this inode */ |
| 1281 | if (error == 0 && dentry->d_inode != NULL) | 1304 | if (error == 0 && dentry->d_inode != NULL) |
| 1282 | clear_nlink(dentry->d_inode); | 1305 | clear_nlink(dentry->d_inode); |
| 1306 | else if (error == -ENOENT) | ||
| 1307 | nfs_dentry_handle_enoent(dentry); | ||
| 1283 | unlock_kernel(); | 1308 | unlock_kernel(); |
| 1284 | 1309 | ||
| 1285 | return error; | 1310 | return error; |
| @@ -1386,6 +1411,8 @@ static int nfs_safe_remove(struct dentry *dentry) | |||
| 1386 | nfs_mark_for_revalidate(inode); | 1411 | nfs_mark_for_revalidate(inode); |
| 1387 | } else | 1412 | } else |
| 1388 | error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); | 1413 | error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); |
| 1414 | if (error == -ENOENT) | ||
| 1415 | nfs_dentry_handle_enoent(dentry); | ||
| 1389 | out: | 1416 | out: |
| 1390 | return error; | 1417 | return error; |
| 1391 | } | 1418 | } |
| @@ -1422,7 +1449,7 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry) | |||
| 1422 | spin_unlock(&dentry->d_lock); | 1449 | spin_unlock(&dentry->d_lock); |
| 1423 | spin_unlock(&dcache_lock); | 1450 | spin_unlock(&dcache_lock); |
| 1424 | error = nfs_safe_remove(dentry); | 1451 | error = nfs_safe_remove(dentry); |
| 1425 | if (!error) { | 1452 | if (!error || error == -ENOENT) { |
| 1426 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | 1453 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
| 1427 | } else if (need_rehash) | 1454 | } else if (need_rehash) |
| 1428 | d_rehash(dentry); | 1455 | d_rehash(dentry); |
| @@ -1635,7 +1662,8 @@ out: | |||
| 1635 | d_move(old_dentry, new_dentry); | 1662 | d_move(old_dentry, new_dentry); |
| 1636 | nfs_set_verifier(new_dentry, | 1663 | nfs_set_verifier(new_dentry, |
| 1637 | nfs_save_change_attribute(new_dir)); | 1664 | nfs_save_change_attribute(new_dir)); |
| 1638 | } | 1665 | } else if (error == -ENOENT) |
| 1666 | nfs_dentry_handle_enoent(old_dentry); | ||
| 1639 | 1667 | ||
| 1640 | /* new dentry created? */ | 1668 | /* new dentry created? */ |
| 1641 | if (dentry) | 1669 | if (dentry) |
| @@ -1666,13 +1694,19 @@ int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask) | |||
| 1666 | restart: | 1694 | restart: |
| 1667 | spin_lock(&nfs_access_lru_lock); | 1695 | spin_lock(&nfs_access_lru_lock); |
| 1668 | list_for_each_entry(nfsi, &nfs_access_lru_list, access_cache_inode_lru) { | 1696 | list_for_each_entry(nfsi, &nfs_access_lru_list, access_cache_inode_lru) { |
| 1697 | struct rw_semaphore *s_umount; | ||
| 1669 | struct inode *inode; | 1698 | struct inode *inode; |
| 1670 | 1699 | ||
| 1671 | if (nr_to_scan-- == 0) | 1700 | if (nr_to_scan-- == 0) |
| 1672 | break; | 1701 | break; |
| 1702 | s_umount = &nfsi->vfs_inode.i_sb->s_umount; | ||
| 1703 | if (!down_read_trylock(s_umount)) | ||
| 1704 | continue; | ||
| 1673 | inode = igrab(&nfsi->vfs_inode); | 1705 | inode = igrab(&nfsi->vfs_inode); |
| 1674 | if (inode == NULL) | 1706 | if (inode == NULL) { |
| 1707 | up_read(s_umount); | ||
| 1675 | continue; | 1708 | continue; |
| 1709 | } | ||
| 1676 | spin_lock(&inode->i_lock); | 1710 | spin_lock(&inode->i_lock); |
| 1677 | if (list_empty(&nfsi->access_cache_entry_lru)) | 1711 | if (list_empty(&nfsi->access_cache_entry_lru)) |
| 1678 | goto remove_lru_entry; | 1712 | goto remove_lru_entry; |
| @@ -1691,6 +1725,7 @@ remove_lru_entry: | |||
| 1691 | spin_unlock(&inode->i_lock); | 1725 | spin_unlock(&inode->i_lock); |
| 1692 | spin_unlock(&nfs_access_lru_lock); | 1726 | spin_unlock(&nfs_access_lru_lock); |
| 1693 | iput(inode); | 1727 | iput(inode); |
| 1728 | up_read(s_umount); | ||
| 1694 | goto restart; | 1729 | goto restart; |
| 1695 | } | 1730 | } |
| 1696 | spin_unlock(&nfs_access_lru_lock); | 1731 | spin_unlock(&nfs_access_lru_lock); |
| @@ -1731,7 +1766,7 @@ static void __nfs_access_zap_cache(struct inode *inode) | |||
| 1731 | void nfs_access_zap_cache(struct inode *inode) | 1766 | void nfs_access_zap_cache(struct inode *inode) |
| 1732 | { | 1767 | { |
| 1733 | /* Remove from global LRU init */ | 1768 | /* Remove from global LRU init */ |
| 1734 | if (test_and_clear_bit(NFS_INO_ACL_LRU_SET, &NFS_FLAGS(inode))) { | 1769 | if (test_and_clear_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) { |
| 1735 | spin_lock(&nfs_access_lru_lock); | 1770 | spin_lock(&nfs_access_lru_lock); |
| 1736 | list_del_init(&NFS_I(inode)->access_cache_inode_lru); | 1771 | list_del_init(&NFS_I(inode)->access_cache_inode_lru); |
| 1737 | spin_unlock(&nfs_access_lru_lock); | 1772 | spin_unlock(&nfs_access_lru_lock); |
| @@ -1845,7 +1880,7 @@ static void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *s | |||
| 1845 | smp_mb__after_atomic_inc(); | 1880 | smp_mb__after_atomic_inc(); |
| 1846 | 1881 | ||
| 1847 | /* Add inode to global LRU list */ | 1882 | /* Add inode to global LRU list */ |
| 1848 | if (!test_and_set_bit(NFS_INO_ACL_LRU_SET, &NFS_FLAGS(inode))) { | 1883 | if (!test_and_set_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) { |
| 1849 | spin_lock(&nfs_access_lru_lock); | 1884 | spin_lock(&nfs_access_lru_lock); |
| 1850 | list_add_tail(&NFS_I(inode)->access_cache_inode_lru, &nfs_access_lru_list); | 1885 | list_add_tail(&NFS_I(inode)->access_cache_inode_lru, &nfs_access_lru_list); |
| 1851 | spin_unlock(&nfs_access_lru_lock); | 1886 | spin_unlock(&nfs_access_lru_lock); |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 3c9d16b4f80c..f8e165c7d5a6 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
| @@ -188,12 +188,17 @@ static void nfs_direct_req_release(struct nfs_direct_req *dreq) | |||
| 188 | static ssize_t nfs_direct_wait(struct nfs_direct_req *dreq) | 188 | static ssize_t nfs_direct_wait(struct nfs_direct_req *dreq) |
| 189 | { | 189 | { |
| 190 | ssize_t result = -EIOCBQUEUED; | 190 | ssize_t result = -EIOCBQUEUED; |
| 191 | struct rpc_clnt *clnt; | ||
| 192 | sigset_t oldset; | ||
| 191 | 193 | ||
| 192 | /* Async requests don't wait here */ | 194 | /* Async requests don't wait here */ |
| 193 | if (dreq->iocb) | 195 | if (dreq->iocb) |
| 194 | goto out; | 196 | goto out; |
| 195 | 197 | ||
| 198 | clnt = NFS_CLIENT(dreq->inode); | ||
| 199 | rpc_clnt_sigmask(clnt, &oldset); | ||
| 196 | result = wait_for_completion_interruptible(&dreq->completion); | 200 | result = wait_for_completion_interruptible(&dreq->completion); |
| 201 | rpc_clnt_sigunmask(clnt, &oldset); | ||
| 197 | 202 | ||
| 198 | if (!result) | 203 | if (!result) |
| 199 | result = dreq->error; | 204 | result = dreq->error; |
| @@ -272,6 +277,16 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, | |||
| 272 | unsigned long user_addr = (unsigned long)iov->iov_base; | 277 | unsigned long user_addr = (unsigned long)iov->iov_base; |
| 273 | size_t count = iov->iov_len; | 278 | size_t count = iov->iov_len; |
| 274 | size_t rsize = NFS_SERVER(inode)->rsize; | 279 | size_t rsize = NFS_SERVER(inode)->rsize; |
| 280 | struct rpc_task *task; | ||
| 281 | struct rpc_message msg = { | ||
| 282 | .rpc_cred = ctx->cred, | ||
| 283 | }; | ||
| 284 | struct rpc_task_setup task_setup_data = { | ||
| 285 | .rpc_client = NFS_CLIENT(inode), | ||
| 286 | .rpc_message = &msg, | ||
| 287 | .callback_ops = &nfs_read_direct_ops, | ||
| 288 | .flags = RPC_TASK_ASYNC, | ||
| 289 | }; | ||
| 275 | unsigned int pgbase; | 290 | unsigned int pgbase; |
| 276 | int result; | 291 | int result; |
| 277 | ssize_t started = 0; | 292 | ssize_t started = 0; |
| @@ -311,7 +326,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, | |||
| 311 | 326 | ||
| 312 | data->req = (struct nfs_page *) dreq; | 327 | data->req = (struct nfs_page *) dreq; |
| 313 | data->inode = inode; | 328 | data->inode = inode; |
| 314 | data->cred = ctx->cred; | 329 | data->cred = msg.rpc_cred; |
| 315 | data->args.fh = NFS_FH(inode); | 330 | data->args.fh = NFS_FH(inode); |
| 316 | data->args.context = ctx; | 331 | data->args.context = ctx; |
| 317 | data->args.offset = pos; | 332 | data->args.offset = pos; |
| @@ -321,14 +336,16 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, | |||
| 321 | data->res.fattr = &data->fattr; | 336 | data->res.fattr = &data->fattr; |
| 322 | data->res.eof = 0; | 337 | data->res.eof = 0; |
| 323 | data->res.count = bytes; | 338 | data->res.count = bytes; |
| 339 | msg.rpc_argp = &data->args; | ||
| 340 | msg.rpc_resp = &data->res; | ||
| 324 | 341 | ||
| 325 | rpc_init_task(&data->task, NFS_CLIENT(inode), RPC_TASK_ASYNC, | 342 | task_setup_data.task = &data->task; |
| 326 | &nfs_read_direct_ops, data); | 343 | task_setup_data.callback_data = data; |
| 327 | NFS_PROTO(inode)->read_setup(data); | 344 | NFS_PROTO(inode)->read_setup(data, &msg); |
| 328 | |||
| 329 | data->task.tk_cookie = (unsigned long) inode; | ||
| 330 | 345 | ||
| 331 | rpc_execute(&data->task); | 346 | task = rpc_run_task(&task_setup_data); |
| 347 | if (!IS_ERR(task)) | ||
| 348 | rpc_put_task(task); | ||
| 332 | 349 | ||
| 333 | dprintk("NFS: %5u initiated direct read call " | 350 | dprintk("NFS: %5u initiated direct read call " |
| 334 | "(req %s/%Ld, %zu bytes @ offset %Lu)\n", | 351 | "(req %s/%Ld, %zu bytes @ offset %Lu)\n", |
| @@ -391,9 +408,7 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov, | |||
| 391 | unsigned long nr_segs, loff_t pos) | 408 | unsigned long nr_segs, loff_t pos) |
| 392 | { | 409 | { |
| 393 | ssize_t result = 0; | 410 | ssize_t result = 0; |
| 394 | sigset_t oldset; | ||
| 395 | struct inode *inode = iocb->ki_filp->f_mapping->host; | 411 | struct inode *inode = iocb->ki_filp->f_mapping->host; |
| 396 | struct rpc_clnt *clnt = NFS_CLIENT(inode); | ||
| 397 | struct nfs_direct_req *dreq; | 412 | struct nfs_direct_req *dreq; |
| 398 | 413 | ||
| 399 | dreq = nfs_direct_req_alloc(); | 414 | dreq = nfs_direct_req_alloc(); |
| @@ -405,11 +420,9 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov, | |||
| 405 | if (!is_sync_kiocb(iocb)) | 420 | if (!is_sync_kiocb(iocb)) |
| 406 | dreq->iocb = iocb; | 421 | dreq->iocb = iocb; |
| 407 | 422 | ||
| 408 | rpc_clnt_sigmask(clnt, &oldset); | ||
| 409 | result = nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos); | 423 | result = nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos); |
| 410 | if (!result) | 424 | if (!result) |
| 411 | result = nfs_direct_wait(dreq); | 425 | result = nfs_direct_wait(dreq); |
| 412 | rpc_clnt_sigunmask(clnt, &oldset); | ||
| 413 | nfs_direct_req_release(dreq); | 426 | nfs_direct_req_release(dreq); |
| 414 | 427 | ||
| 415 | return result; | 428 | return result; |
| @@ -431,6 +444,15 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) | |||
| 431 | struct inode *inode = dreq->inode; | 444 | struct inode *inode = dreq->inode; |
| 432 | struct list_head *p; | 445 | struct list_head *p; |
| 433 | struct nfs_write_data *data; | 446 | struct nfs_write_data *data; |
| 447 | struct rpc_task *task; | ||
| 448 | struct rpc_message msg = { | ||
| 449 | .rpc_cred = dreq->ctx->cred, | ||
| 450 | }; | ||
| 451 | struct rpc_task_setup task_setup_data = { | ||
| 452 | .rpc_client = NFS_CLIENT(inode), | ||
| 453 | .callback_ops = &nfs_write_direct_ops, | ||
| 454 | .flags = RPC_TASK_ASYNC, | ||
| 455 | }; | ||
| 434 | 456 | ||
| 435 | dreq->count = 0; | 457 | dreq->count = 0; |
| 436 | get_dreq(dreq); | 458 | get_dreq(dreq); |
| @@ -440,6 +462,9 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) | |||
| 440 | 462 | ||
| 441 | get_dreq(dreq); | 463 | get_dreq(dreq); |
| 442 | 464 | ||
| 465 | /* Use stable writes */ | ||
| 466 | data->args.stable = NFS_FILE_SYNC; | ||
| 467 | |||
| 443 | /* | 468 | /* |
| 444 | * Reset data->res. | 469 | * Reset data->res. |
| 445 | */ | 470 | */ |
| @@ -451,17 +476,18 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) | |||
| 451 | * Reuse data->task; data->args should not have changed | 476 | * Reuse data->task; data->args should not have changed |
| 452 | * since the original request was sent. | 477 | * since the original request was sent. |
| 453 | */ | 478 | */ |
| 454 | rpc_init_task(&data->task, NFS_CLIENT(inode), RPC_TASK_ASYNC, | 479 | task_setup_data.task = &data->task; |
| 455 | &nfs_write_direct_ops, data); | 480 | task_setup_data.callback_data = data; |
| 456 | NFS_PROTO(inode)->write_setup(data, FLUSH_STABLE); | 481 | msg.rpc_argp = &data->args; |
| 457 | 482 | msg.rpc_resp = &data->res; | |
| 458 | data->task.tk_priority = RPC_PRIORITY_NORMAL; | 483 | NFS_PROTO(inode)->write_setup(data, &msg); |
| 459 | data->task.tk_cookie = (unsigned long) inode; | ||
| 460 | 484 | ||
| 461 | /* | 485 | /* |
| 462 | * We're called via an RPC callback, so BKL is already held. | 486 | * We're called via an RPC callback, so BKL is already held. |
| 463 | */ | 487 | */ |
| 464 | rpc_execute(&data->task); | 488 | task = rpc_run_task(&task_setup_data); |
| 489 | if (!IS_ERR(task)) | ||
| 490 | rpc_put_task(task); | ||
| 465 | 491 | ||
| 466 | dprintk("NFS: %5u rescheduled direct write call (req %s/%Ld, %u bytes @ offset %Lu)\n", | 492 | dprintk("NFS: %5u rescheduled direct write call (req %s/%Ld, %u bytes @ offset %Lu)\n", |
| 467 | data->task.tk_pid, | 493 | data->task.tk_pid, |
| @@ -504,9 +530,23 @@ static const struct rpc_call_ops nfs_commit_direct_ops = { | |||
| 504 | static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) | 530 | static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) |
| 505 | { | 531 | { |
| 506 | struct nfs_write_data *data = dreq->commit_data; | 532 | struct nfs_write_data *data = dreq->commit_data; |
| 533 | struct rpc_task *task; | ||
| 534 | struct rpc_message msg = { | ||
| 535 | .rpc_argp = &data->args, | ||
| 536 | .rpc_resp = &data->res, | ||
| 537 | .rpc_cred = dreq->ctx->cred, | ||
| 538 | }; | ||
| 539 | struct rpc_task_setup task_setup_data = { | ||
| 540 | .task = &data->task, | ||
| 541 | .rpc_client = NFS_CLIENT(dreq->inode), | ||
| 542 | .rpc_message = &msg, | ||
| 543 | .callback_ops = &nfs_commit_direct_ops, | ||
| 544 | .callback_data = data, | ||
| 545 | .flags = RPC_TASK_ASYNC, | ||
| 546 | }; | ||
| 507 | 547 | ||
| 508 | data->inode = dreq->inode; | 548 | data->inode = dreq->inode; |
| 509 | data->cred = dreq->ctx->cred; | 549 | data->cred = msg.rpc_cred; |
| 510 | 550 | ||
| 511 | data->args.fh = NFS_FH(data->inode); | 551 | data->args.fh = NFS_FH(data->inode); |
| 512 | data->args.offset = 0; | 552 | data->args.offset = 0; |
| @@ -515,18 +555,16 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) | |||
| 515 | data->res.fattr = &data->fattr; | 555 | data->res.fattr = &data->fattr; |
| 516 | data->res.verf = &data->verf; | 556 | data->res.verf = &data->verf; |
| 517 | 557 | ||
| 518 | rpc_init_task(&data->task, NFS_CLIENT(dreq->inode), RPC_TASK_ASYNC, | 558 | NFS_PROTO(data->inode)->commit_setup(data, &msg); |
| 519 | &nfs_commit_direct_ops, data); | ||
| 520 | NFS_PROTO(data->inode)->commit_setup(data, 0); | ||
| 521 | 559 | ||
| 522 | data->task.tk_priority = RPC_PRIORITY_NORMAL; | ||
| 523 | data->task.tk_cookie = (unsigned long)data->inode; | ||
| 524 | /* Note: task.tk_ops->rpc_release will free dreq->commit_data */ | 560 | /* Note: task.tk_ops->rpc_release will free dreq->commit_data */ |
| 525 | dreq->commit_data = NULL; | 561 | dreq->commit_data = NULL; |
| 526 | 562 | ||
| 527 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); | 563 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); |
| 528 | 564 | ||
| 529 | rpc_execute(&data->task); | 565 | task = rpc_run_task(&task_setup_data); |
| 566 | if (!IS_ERR(task)) | ||
| 567 | rpc_put_task(task); | ||
| 530 | } | 568 | } |
| 531 | 569 | ||
| 532 | static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode) | 570 | static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode) |
| @@ -641,6 +679,16 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, | |||
| 641 | struct inode *inode = ctx->path.dentry->d_inode; | 679 | struct inode *inode = ctx->path.dentry->d_inode; |
| 642 | unsigned long user_addr = (unsigned long)iov->iov_base; | 680 | unsigned long user_addr = (unsigned long)iov->iov_base; |
| 643 | size_t count = iov->iov_len; | 681 | size_t count = iov->iov_len; |
| 682 | struct rpc_task *task; | ||
| 683 | struct rpc_message msg = { | ||
| 684 | .rpc_cred = ctx->cred, | ||
| 685 | }; | ||
| 686 | struct rpc_task_setup task_setup_data = { | ||
| 687 | .rpc_client = NFS_CLIENT(inode), | ||
| 688 | .rpc_message = &msg, | ||
| 689 | .callback_ops = &nfs_write_direct_ops, | ||
| 690 | .flags = RPC_TASK_ASYNC, | ||
| 691 | }; | ||
| 644 | size_t wsize = NFS_SERVER(inode)->wsize; | 692 | size_t wsize = NFS_SERVER(inode)->wsize; |
| 645 | unsigned int pgbase; | 693 | unsigned int pgbase; |
| 646 | int result; | 694 | int result; |
| @@ -683,25 +731,27 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, | |||
| 683 | 731 | ||
| 684 | data->req = (struct nfs_page *) dreq; | 732 | data->req = (struct nfs_page *) dreq; |
| 685 | data->inode = inode; | 733 | data->inode = inode; |
| 686 | data->cred = ctx->cred; | 734 | data->cred = msg.rpc_cred; |
| 687 | data->args.fh = NFS_FH(inode); | 735 | data->args.fh = NFS_FH(inode); |
| 688 | data->args.context = ctx; | 736 | data->args.context = ctx; |
| 689 | data->args.offset = pos; | 737 | data->args.offset = pos; |
| 690 | data->args.pgbase = pgbase; | 738 | data->args.pgbase = pgbase; |
| 691 | data->args.pages = data->pagevec; | 739 | data->args.pages = data->pagevec; |
| 692 | data->args.count = bytes; | 740 | data->args.count = bytes; |
| 741 | data->args.stable = sync; | ||
| 693 | data->res.fattr = &data->fattr; | 742 | data->res.fattr = &data->fattr; |
| 694 | data->res.count = bytes; | 743 | data->res.count = bytes; |
| 695 | data->res.verf = &data->verf; | 744 | data->res.verf = &data->verf; |
| 696 | 745 | ||
| 697 | rpc_init_task(&data->task, NFS_CLIENT(inode), RPC_TASK_ASYNC, | 746 | task_setup_data.task = &data->task; |
| 698 | &nfs_write_direct_ops, data); | 747 | task_setup_data.callback_data = data; |
| 699 | NFS_PROTO(inode)->write_setup(data, sync); | 748 | msg.rpc_argp = &data->args; |
| 700 | 749 | msg.rpc_resp = &data->res; | |
| 701 | data->task.tk_priority = RPC_PRIORITY_NORMAL; | 750 | NFS_PROTO(inode)->write_setup(data, &msg); |
| 702 | data->task.tk_cookie = (unsigned long) inode; | ||
| 703 | 751 | ||
| 704 | rpc_execute(&data->task); | 752 | task = rpc_run_task(&task_setup_data); |
| 753 | if (!IS_ERR(task)) | ||
| 754 | rpc_put_task(task); | ||
| 705 | 755 | ||
| 706 | dprintk("NFS: %5u initiated direct write call " | 756 | dprintk("NFS: %5u initiated direct write call " |
| 707 | "(req %s/%Ld, %zu bytes @ offset %Lu)\n", | 757 | "(req %s/%Ld, %zu bytes @ offset %Lu)\n", |
| @@ -767,12 +817,10 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov, | |||
| 767 | size_t count) | 817 | size_t count) |
| 768 | { | 818 | { |
| 769 | ssize_t result = 0; | 819 | ssize_t result = 0; |
| 770 | sigset_t oldset; | ||
| 771 | struct inode *inode = iocb->ki_filp->f_mapping->host; | 820 | struct inode *inode = iocb->ki_filp->f_mapping->host; |
| 772 | struct rpc_clnt *clnt = NFS_CLIENT(inode); | ||
| 773 | struct nfs_direct_req *dreq; | 821 | struct nfs_direct_req *dreq; |
| 774 | size_t wsize = NFS_SERVER(inode)->wsize; | 822 | size_t wsize = NFS_SERVER(inode)->wsize; |
| 775 | int sync = 0; | 823 | int sync = NFS_UNSTABLE; |
| 776 | 824 | ||
| 777 | dreq = nfs_direct_req_alloc(); | 825 | dreq = nfs_direct_req_alloc(); |
| 778 | if (!dreq) | 826 | if (!dreq) |
| @@ -780,18 +828,16 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov, | |||
| 780 | nfs_alloc_commit_data(dreq); | 828 | nfs_alloc_commit_data(dreq); |
| 781 | 829 | ||
| 782 | if (dreq->commit_data == NULL || count < wsize) | 830 | if (dreq->commit_data == NULL || count < wsize) |
| 783 | sync = FLUSH_STABLE; | 831 | sync = NFS_FILE_SYNC; |
| 784 | 832 | ||
| 785 | dreq->inode = inode; | 833 | dreq->inode = inode; |
| 786 | dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); | 834 | dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); |
| 787 | if (!is_sync_kiocb(iocb)) | 835 | if (!is_sync_kiocb(iocb)) |
| 788 | dreq->iocb = iocb; | 836 | dreq->iocb = iocb; |
| 789 | 837 | ||
| 790 | rpc_clnt_sigmask(clnt, &oldset); | ||
| 791 | result = nfs_direct_write_schedule_iovec(dreq, iov, nr_segs, pos, sync); | 838 | result = nfs_direct_write_schedule_iovec(dreq, iov, nr_segs, pos, sync); |
| 792 | if (!result) | 839 | if (!result) |
| 793 | result = nfs_direct_wait(dreq); | 840 | result = nfs_direct_wait(dreq); |
| 794 | rpc_clnt_sigunmask(clnt, &oldset); | ||
| 795 | nfs_direct_req_release(dreq); | 841 | nfs_direct_req_release(dreq); |
| 796 | 842 | ||
| 797 | return result; | 843 | return result; |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index b3bb89f7d5d2..ef57a5ae5904 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
| @@ -349,7 +349,9 @@ static int nfs_write_end(struct file *file, struct address_space *mapping, | |||
| 349 | unlock_page(page); | 349 | unlock_page(page); |
| 350 | page_cache_release(page); | 350 | page_cache_release(page); |
| 351 | 351 | ||
| 352 | return status < 0 ? status : copied; | 352 | if (status < 0) |
| 353 | return status; | ||
| 354 | return copied; | ||
| 353 | } | 355 | } |
| 354 | 356 | ||
| 355 | static void nfs_invalidate_page(struct page *page, unsigned long offset) | 357 | static void nfs_invalidate_page(struct page *page, unsigned long offset) |
| @@ -392,35 +394,27 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page) | |||
| 392 | struct file *filp = vma->vm_file; | 394 | struct file *filp = vma->vm_file; |
| 393 | unsigned pagelen; | 395 | unsigned pagelen; |
| 394 | int ret = -EINVAL; | 396 | int ret = -EINVAL; |
| 395 | void *fsdata; | ||
| 396 | struct address_space *mapping; | 397 | struct address_space *mapping; |
| 397 | loff_t offset; | ||
| 398 | 398 | ||
| 399 | lock_page(page); | 399 | lock_page(page); |
| 400 | mapping = page->mapping; | 400 | mapping = page->mapping; |
| 401 | if (mapping != vma->vm_file->f_path.dentry->d_inode->i_mapping) { | 401 | if (mapping != vma->vm_file->f_path.dentry->d_inode->i_mapping) |
| 402 | unlock_page(page); | 402 | goto out_unlock; |
| 403 | return -EINVAL; | 403 | |
| 404 | } | 404 | ret = 0; |
| 405 | pagelen = nfs_page_length(page); | 405 | pagelen = nfs_page_length(page); |
| 406 | offset = (loff_t)page->index << PAGE_CACHE_SHIFT; | 406 | if (pagelen == 0) |
| 407 | unlock_page(page); | 407 | goto out_unlock; |
| 408 | 408 | ||
| 409 | /* | 409 | ret = nfs_flush_incompatible(filp, page); |
| 410 | * we can use mapping after releasing the page lock, because: | 410 | if (ret != 0) |
| 411 | * we hold mmap_sem on the fault path, which should pin the vma | 411 | goto out_unlock; |
| 412 | * which should pin the file, which pins the dentry which should | ||
| 413 | * hold a reference on inode. | ||
| 414 | */ | ||
| 415 | 412 | ||
| 416 | if (pagelen) { | 413 | ret = nfs_updatepage(filp, page, 0, pagelen); |
| 417 | struct page *page2 = NULL; | 414 | if (ret == 0) |
| 418 | ret = nfs_write_begin(filp, mapping, offset, pagelen, | 415 | ret = pagelen; |
| 419 | 0, &page2, &fsdata); | 416 | out_unlock: |
| 420 | if (!ret) | 417 | unlock_page(page); |
| 421 | ret = nfs_write_end(filp, mapping, offset, pagelen, | ||
| 422 | pagelen, page2, fsdata); | ||
| 423 | } | ||
| 424 | return ret; | 418 | return ret; |
| 425 | } | 419 | } |
| 426 | 420 | ||
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index d11eb055265c..8ae5dba2d4e5 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c | |||
| @@ -72,39 +72,39 @@ module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int, | |||
| 72 | &nfs_idmap_cache_timeout, 0644); | 72 | &nfs_idmap_cache_timeout, 0644); |
| 73 | 73 | ||
| 74 | struct idmap_hashent { | 74 | struct idmap_hashent { |
| 75 | unsigned long ih_expires; | 75 | unsigned long ih_expires; |
| 76 | __u32 ih_id; | 76 | __u32 ih_id; |
| 77 | int ih_namelen; | 77 | size_t ih_namelen; |
| 78 | char ih_name[IDMAP_NAMESZ]; | 78 | char ih_name[IDMAP_NAMESZ]; |
| 79 | }; | 79 | }; |
| 80 | 80 | ||
| 81 | struct idmap_hashtable { | 81 | struct idmap_hashtable { |
| 82 | __u8 h_type; | 82 | __u8 h_type; |
| 83 | struct idmap_hashent h_entries[IDMAP_HASH_SZ]; | 83 | struct idmap_hashent h_entries[IDMAP_HASH_SZ]; |
| 84 | }; | 84 | }; |
| 85 | 85 | ||
| 86 | struct idmap { | 86 | struct idmap { |
| 87 | struct dentry *idmap_dentry; | 87 | struct dentry *idmap_dentry; |
| 88 | wait_queue_head_t idmap_wq; | 88 | wait_queue_head_t idmap_wq; |
| 89 | struct idmap_msg idmap_im; | 89 | struct idmap_msg idmap_im; |
| 90 | struct mutex idmap_lock; /* Serializes upcalls */ | 90 | struct mutex idmap_lock; /* Serializes upcalls */ |
| 91 | struct mutex idmap_im_lock; /* Protects the hashtable */ | 91 | struct mutex idmap_im_lock; /* Protects the hashtable */ |
| 92 | struct idmap_hashtable idmap_user_hash; | 92 | struct idmap_hashtable idmap_user_hash; |
| 93 | struct idmap_hashtable idmap_group_hash; | 93 | struct idmap_hashtable idmap_group_hash; |
| 94 | }; | 94 | }; |
| 95 | 95 | ||
| 96 | static ssize_t idmap_pipe_upcall(struct file *, struct rpc_pipe_msg *, | 96 | static ssize_t idmap_pipe_upcall(struct file *, struct rpc_pipe_msg *, |
| 97 | char __user *, size_t); | 97 | char __user *, size_t); |
| 98 | static ssize_t idmap_pipe_downcall(struct file *, const char __user *, | 98 | static ssize_t idmap_pipe_downcall(struct file *, const char __user *, |
| 99 | size_t); | 99 | size_t); |
| 100 | static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *); | 100 | static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *); |
| 101 | 101 | ||
| 102 | static unsigned int fnvhash32(const void *, size_t); | 102 | static unsigned int fnvhash32(const void *, size_t); |
| 103 | 103 | ||
| 104 | static struct rpc_pipe_ops idmap_upcall_ops = { | 104 | static struct rpc_pipe_ops idmap_upcall_ops = { |
| 105 | .upcall = idmap_pipe_upcall, | 105 | .upcall = idmap_pipe_upcall, |
| 106 | .downcall = idmap_pipe_downcall, | 106 | .downcall = idmap_pipe_downcall, |
| 107 | .destroy_msg = idmap_pipe_destroy_msg, | 107 | .destroy_msg = idmap_pipe_destroy_msg, |
| 108 | }; | 108 | }; |
| 109 | 109 | ||
| 110 | int | 110 | int |
| @@ -115,19 +115,20 @@ nfs_idmap_new(struct nfs_client *clp) | |||
| 115 | 115 | ||
| 116 | BUG_ON(clp->cl_idmap != NULL); | 116 | BUG_ON(clp->cl_idmap != NULL); |
| 117 | 117 | ||
| 118 | if ((idmap = kzalloc(sizeof(*idmap), GFP_KERNEL)) == NULL) | 118 | idmap = kzalloc(sizeof(*idmap), GFP_KERNEL); |
| 119 | return -ENOMEM; | 119 | if (idmap == NULL) |
| 120 | return -ENOMEM; | ||
| 120 | 121 | ||
| 121 | idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_dentry, "idmap", | 122 | idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_dentry, "idmap", |
| 122 | idmap, &idmap_upcall_ops, 0); | 123 | idmap, &idmap_upcall_ops, 0); |
| 123 | if (IS_ERR(idmap->idmap_dentry)) { | 124 | if (IS_ERR(idmap->idmap_dentry)) { |
| 124 | error = PTR_ERR(idmap->idmap_dentry); | 125 | error = PTR_ERR(idmap->idmap_dentry); |
| 125 | kfree(idmap); | 126 | kfree(idmap); |
| 126 | return error; | 127 | return error; |
| 127 | } | 128 | } |
| 128 | 129 | ||
| 129 | mutex_init(&idmap->idmap_lock); | 130 | mutex_init(&idmap->idmap_lock); |
| 130 | mutex_init(&idmap->idmap_im_lock); | 131 | mutex_init(&idmap->idmap_im_lock); |
| 131 | init_waitqueue_head(&idmap->idmap_wq); | 132 | init_waitqueue_head(&idmap->idmap_wq); |
| 132 | idmap->idmap_user_hash.h_type = IDMAP_TYPE_USER; | 133 | idmap->idmap_user_hash.h_type = IDMAP_TYPE_USER; |
| 133 | idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP; | 134 | idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP; |
| @@ -192,7 +193,7 @@ idmap_lookup_id(struct idmap_hashtable *h, __u32 id) | |||
| 192 | * pretty trivial. | 193 | * pretty trivial. |
| 193 | */ | 194 | */ |
| 194 | static inline struct idmap_hashent * | 195 | static inline struct idmap_hashent * |
| 195 | idmap_alloc_name(struct idmap_hashtable *h, char *name, unsigned len) | 196 | idmap_alloc_name(struct idmap_hashtable *h, char *name, size_t len) |
| 196 | { | 197 | { |
| 197 | return idmap_name_hash(h, name, len); | 198 | return idmap_name_hash(h, name, len); |
| 198 | } | 199 | } |
| @@ -285,7 +286,7 @@ nfs_idmap_id(struct idmap *idmap, struct idmap_hashtable *h, | |||
| 285 | memset(im, 0, sizeof(*im)); | 286 | memset(im, 0, sizeof(*im)); |
| 286 | mutex_unlock(&idmap->idmap_im_lock); | 287 | mutex_unlock(&idmap->idmap_im_lock); |
| 287 | mutex_unlock(&idmap->idmap_lock); | 288 | mutex_unlock(&idmap->idmap_lock); |
| 288 | return (ret); | 289 | return ret; |
| 289 | } | 290 | } |
| 290 | 291 | ||
| 291 | /* | 292 | /* |
| @@ -354,42 +355,40 @@ nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h, | |||
| 354 | /* RPC pipefs upcall/downcall routines */ | 355 | /* RPC pipefs upcall/downcall routines */ |
| 355 | static ssize_t | 356 | static ssize_t |
| 356 | idmap_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg, | 357 | idmap_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg, |
| 357 | char __user *dst, size_t buflen) | 358 | char __user *dst, size_t buflen) |
| 358 | { | 359 | { |
| 359 | char *data = (char *)msg->data + msg->copied; | 360 | char *data = (char *)msg->data + msg->copied; |
| 360 | ssize_t mlen = msg->len - msg->copied; | 361 | size_t mlen = min(msg->len, buflen); |
| 361 | ssize_t left; | 362 | unsigned long left; |
| 362 | 363 | ||
| 363 | if (mlen > buflen) | 364 | left = copy_to_user(dst, data, mlen); |
| 364 | mlen = buflen; | 365 | if (left == mlen) { |
| 365 | 366 | msg->errno = -EFAULT; | |
| 366 | left = copy_to_user(dst, data, mlen); | 367 | return -EFAULT; |
| 367 | if (left < 0) { | ||
| 368 | msg->errno = left; | ||
| 369 | return left; | ||
| 370 | } | 368 | } |
| 369 | |||
| 371 | mlen -= left; | 370 | mlen -= left; |
| 372 | msg->copied += mlen; | 371 | msg->copied += mlen; |
| 373 | msg->errno = 0; | 372 | msg->errno = 0; |
| 374 | return mlen; | 373 | return mlen; |
| 375 | } | 374 | } |
| 376 | 375 | ||
| 377 | static ssize_t | 376 | static ssize_t |
| 378 | idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) | 377 | idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) |
| 379 | { | 378 | { |
| 380 | struct rpc_inode *rpci = RPC_I(filp->f_path.dentry->d_inode); | 379 | struct rpc_inode *rpci = RPC_I(filp->f_path.dentry->d_inode); |
| 381 | struct idmap *idmap = (struct idmap *)rpci->private; | 380 | struct idmap *idmap = (struct idmap *)rpci->private; |
| 382 | struct idmap_msg im_in, *im = &idmap->idmap_im; | 381 | struct idmap_msg im_in, *im = &idmap->idmap_im; |
| 383 | struct idmap_hashtable *h; | 382 | struct idmap_hashtable *h; |
| 384 | struct idmap_hashent *he = NULL; | 383 | struct idmap_hashent *he = NULL; |
| 385 | int namelen_in; | 384 | size_t namelen_in; |
| 386 | int ret; | 385 | int ret; |
| 387 | 386 | ||
| 388 | if (mlen != sizeof(im_in)) | 387 | if (mlen != sizeof(im_in)) |
| 389 | return (-ENOSPC); | 388 | return -ENOSPC; |
| 390 | 389 | ||
| 391 | if (copy_from_user(&im_in, src, mlen) != 0) | 390 | if (copy_from_user(&im_in, src, mlen) != 0) |
| 392 | return (-EFAULT); | 391 | return -EFAULT; |
| 393 | 392 | ||
| 394 | mutex_lock(&idmap->idmap_im_lock); | 393 | mutex_lock(&idmap->idmap_im_lock); |
| 395 | 394 | ||
| @@ -487,7 +486,7 @@ static unsigned int fnvhash32(const void *buf, size_t buflen) | |||
| 487 | hash ^= (unsigned int)*p; | 486 | hash ^= (unsigned int)*p; |
| 488 | } | 487 | } |
| 489 | 488 | ||
| 490 | return (hash); | 489 | return hash; |
| 491 | } | 490 | } |
| 492 | 491 | ||
| 493 | int nfs_map_name_to_uid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid) | 492 | int nfs_map_name_to_uid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid) |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index db5d96dc6107..3f332e54e760 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
| @@ -192,7 +192,7 @@ void nfs_invalidate_atime(struct inode *inode) | |||
| 192 | */ | 192 | */ |
| 193 | static void nfs_invalidate_inode(struct inode *inode) | 193 | static void nfs_invalidate_inode(struct inode *inode) |
| 194 | { | 194 | { |
| 195 | set_bit(NFS_INO_STALE, &NFS_FLAGS(inode)); | 195 | set_bit(NFS_INO_STALE, &NFS_I(inode)->flags); |
| 196 | nfs_zap_caches_locked(inode); | 196 | nfs_zap_caches_locked(inode); |
| 197 | } | 197 | } |
| 198 | 198 | ||
| @@ -229,7 +229,7 @@ nfs_init_locked(struct inode *inode, void *opaque) | |||
| 229 | struct nfs_find_desc *desc = (struct nfs_find_desc *)opaque; | 229 | struct nfs_find_desc *desc = (struct nfs_find_desc *)opaque; |
| 230 | struct nfs_fattr *fattr = desc->fattr; | 230 | struct nfs_fattr *fattr = desc->fattr; |
| 231 | 231 | ||
| 232 | NFS_FILEID(inode) = fattr->fileid; | 232 | set_nfs_fileid(inode, fattr->fileid); |
| 233 | nfs_copy_fh(NFS_FH(inode), desc->fh); | 233 | nfs_copy_fh(NFS_FH(inode), desc->fh); |
| 234 | return 0; | 234 | return 0; |
| 235 | } | 235 | } |
| @@ -291,7 +291,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
| 291 | inode->i_fop = &nfs_dir_operations; | 291 | inode->i_fop = &nfs_dir_operations; |
| 292 | if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS) | 292 | if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS) |
| 293 | && fattr->size <= NFS_LIMIT_READDIRPLUS) | 293 | && fattr->size <= NFS_LIMIT_READDIRPLUS) |
| 294 | set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode)); | 294 | set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags); |
| 295 | /* Deal with crossing mountpoints */ | 295 | /* Deal with crossing mountpoints */ |
| 296 | if (!nfs_fsid_equal(&NFS_SB(sb)->fsid, &fattr->fsid)) { | 296 | if (!nfs_fsid_equal(&NFS_SB(sb)->fsid, &fattr->fsid)) { |
| 297 | if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) | 297 | if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) |
| @@ -461,9 +461,18 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | |||
| 461 | int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME; | 461 | int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME; |
| 462 | int err; | 462 | int err; |
| 463 | 463 | ||
| 464 | /* Flush out writes to the server in order to update c/mtime */ | 464 | /* |
| 465 | if (S_ISREG(inode->i_mode)) | 465 | * Flush out writes to the server in order to update c/mtime. |
| 466 | * | ||
| 467 | * Hold the i_mutex to suspend application writes temporarily; | ||
| 468 | * this prevents long-running writing applications from blocking | ||
| 469 | * nfs_wb_nocommit. | ||
| 470 | */ | ||
| 471 | if (S_ISREG(inode->i_mode)) { | ||
| 472 | mutex_lock(&inode->i_mutex); | ||
| 466 | nfs_wb_nocommit(inode); | 473 | nfs_wb_nocommit(inode); |
| 474 | mutex_unlock(&inode->i_mutex); | ||
| 475 | } | ||
| 467 | 476 | ||
| 468 | /* | 477 | /* |
| 469 | * We may force a getattr if the user cares about atime. | 478 | * We may force a getattr if the user cares about atime. |
| @@ -659,7 +668,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
| 659 | if (status == -ESTALE) { | 668 | if (status == -ESTALE) { |
| 660 | nfs_zap_caches(inode); | 669 | nfs_zap_caches(inode); |
| 661 | if (!S_ISDIR(inode->i_mode)) | 670 | if (!S_ISDIR(inode->i_mode)) |
| 662 | set_bit(NFS_INO_STALE, &NFS_FLAGS(inode)); | 671 | set_bit(NFS_INO_STALE, &NFS_I(inode)->flags); |
| 663 | } | 672 | } |
| 664 | goto out; | 673 | goto out; |
| 665 | } | 674 | } |
| @@ -814,8 +823,9 @@ static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
| 814 | if (S_ISDIR(inode->i_mode)) | 823 | if (S_ISDIR(inode->i_mode)) |
| 815 | nfsi->cache_validity |= NFS_INO_INVALID_DATA; | 824 | nfsi->cache_validity |= NFS_INO_INVALID_DATA; |
| 816 | } | 825 | } |
| 817 | if (inode->i_size == fattr->pre_size && nfsi->npages == 0) | 826 | if (inode->i_size == nfs_size_to_loff_t(fattr->pre_size) && |
| 818 | inode->i_size = fattr->size; | 827 | nfsi->npages == 0) |
| 828 | inode->i_size = nfs_size_to_loff_t(fattr->size); | ||
| 819 | } | 829 | } |
| 820 | } | 830 | } |
| 821 | 831 | ||
| @@ -1019,7 +1029,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
| 1019 | dprintk("NFS: mtime change on server for file %s/%ld\n", | 1029 | dprintk("NFS: mtime change on server for file %s/%ld\n", |
| 1020 | inode->i_sb->s_id, inode->i_ino); | 1030 | inode->i_sb->s_id, inode->i_ino); |
| 1021 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; | 1031 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; |
| 1022 | nfsi->cache_change_attribute = now; | 1032 | if (S_ISDIR(inode->i_mode)) |
| 1033 | nfs_force_lookup_revalidate(inode); | ||
| 1023 | } | 1034 | } |
| 1024 | /* If ctime has changed we should definitely clear access+acl caches */ | 1035 | /* If ctime has changed we should definitely clear access+acl caches */ |
| 1025 | if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) | 1036 | if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) |
| @@ -1028,7 +1039,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
| 1028 | dprintk("NFS: change_attr change on server for file %s/%ld\n", | 1039 | dprintk("NFS: change_attr change on server for file %s/%ld\n", |
| 1029 | inode->i_sb->s_id, inode->i_ino); | 1040 | inode->i_sb->s_id, inode->i_ino); |
| 1030 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; | 1041 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; |
| 1031 | nfsi->cache_change_attribute = now; | 1042 | if (S_ISDIR(inode->i_mode)) |
| 1043 | nfs_force_lookup_revalidate(inode); | ||
| 1032 | } | 1044 | } |
| 1033 | 1045 | ||
| 1034 | /* Check if our cached file size is stale */ | 1046 | /* Check if our cached file size is stale */ |
| @@ -1133,7 +1145,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
| 1133 | void nfs4_clear_inode(struct inode *inode) | 1145 | void nfs4_clear_inode(struct inode *inode) |
| 1134 | { | 1146 | { |
| 1135 | /* If we are holding a delegation, return it! */ | 1147 | /* If we are holding a delegation, return it! */ |
| 1136 | nfs_inode_return_delegation(inode); | 1148 | nfs_inode_return_delegation_noreclaim(inode); |
| 1137 | /* First call standard NFS clear_inode() code */ | 1149 | /* First call standard NFS clear_inode() code */ |
| 1138 | nfs_clear_inode(inode); | 1150 | nfs_clear_inode(inode); |
| 1139 | } | 1151 | } |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index f3acf48412be..0f5619611b8d 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
| @@ -21,7 +21,8 @@ struct nfs_clone_mount { | |||
| 21 | struct nfs_fattr *fattr; | 21 | struct nfs_fattr *fattr; |
| 22 | char *hostname; | 22 | char *hostname; |
| 23 | char *mnt_path; | 23 | char *mnt_path; |
| 24 | struct sockaddr_in *addr; | 24 | struct sockaddr *addr; |
| 25 | size_t addrlen; | ||
| 25 | rpc_authflavor_t authflavor; | 26 | rpc_authflavor_t authflavor; |
| 26 | }; | 27 | }; |
| 27 | 28 | ||
| @@ -41,19 +42,19 @@ struct nfs_parsed_mount_data { | |||
| 41 | char *client_address; | 42 | char *client_address; |
| 42 | 43 | ||
| 43 | struct { | 44 | struct { |
| 44 | struct sockaddr_in address; | 45 | struct sockaddr_storage address; |
| 46 | size_t addrlen; | ||
| 45 | char *hostname; | 47 | char *hostname; |
| 46 | unsigned int program; | ||
| 47 | unsigned int version; | 48 | unsigned int version; |
| 48 | unsigned short port; | 49 | unsigned short port; |
| 49 | int protocol; | 50 | int protocol; |
| 50 | } mount_server; | 51 | } mount_server; |
| 51 | 52 | ||
| 52 | struct { | 53 | struct { |
| 53 | struct sockaddr_in address; | 54 | struct sockaddr_storage address; |
| 55 | size_t addrlen; | ||
| 54 | char *hostname; | 56 | char *hostname; |
| 55 | char *export_path; | 57 | char *export_path; |
| 56 | unsigned int program; | ||
| 57 | int protocol; | 58 | int protocol; |
| 58 | } nfs_server; | 59 | } nfs_server; |
| 59 | }; | 60 | }; |
| @@ -62,7 +63,8 @@ struct nfs_parsed_mount_data { | |||
| 62 | extern struct rpc_program nfs_program; | 63 | extern struct rpc_program nfs_program; |
| 63 | 64 | ||
| 64 | extern void nfs_put_client(struct nfs_client *); | 65 | extern void nfs_put_client(struct nfs_client *); |
| 65 | extern struct nfs_client *nfs_find_client(const struct sockaddr_in *, int); | 66 | extern struct nfs_client *nfs_find_client(const struct sockaddr *, u32); |
| 67 | extern struct nfs_client *nfs_find_client_next(struct nfs_client *); | ||
| 66 | extern struct nfs_server *nfs_create_server( | 68 | extern struct nfs_server *nfs_create_server( |
| 67 | const struct nfs_parsed_mount_data *, | 69 | const struct nfs_parsed_mount_data *, |
| 68 | struct nfs_fh *); | 70 | struct nfs_fh *); |
| @@ -160,6 +162,8 @@ extern struct rpc_stat nfs_rpcstat; | |||
| 160 | 162 | ||
| 161 | extern int __init register_nfs_fs(void); | 163 | extern int __init register_nfs_fs(void); |
| 162 | extern void __exit unregister_nfs_fs(void); | 164 | extern void __exit unregister_nfs_fs(void); |
| 165 | extern void nfs_sb_active(struct nfs_server *server); | ||
| 166 | extern void nfs_sb_deactive(struct nfs_server *server); | ||
| 163 | 167 | ||
| 164 | /* namespace.c */ | 168 | /* namespace.c */ |
| 165 | extern char *nfs_path(const char *base, | 169 | extern char *nfs_path(const char *base, |
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index acfc56f9edc0..be4ce1c3a3d8 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
| @@ -188,7 +188,7 @@ static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server, | |||
| 188 | { | 188 | { |
| 189 | #ifdef CONFIG_NFS_V4 | 189 | #ifdef CONFIG_NFS_V4 |
| 190 | struct vfsmount *mnt = NULL; | 190 | struct vfsmount *mnt = NULL; |
| 191 | switch (server->nfs_client->cl_nfsversion) { | 191 | switch (server->nfs_client->rpc_ops->version) { |
| 192 | case 2: | 192 | case 2: |
| 193 | case 3: | 193 | case 3: |
| 194 | mnt = vfs_kern_mount(&nfs_xdev_fs_type, 0, devname, mountdata); | 194 | mnt = vfs_kern_mount(&nfs_xdev_fs_type, 0, devname, mountdata); |
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 668ab96c7b59..1f7ea675e0c5 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c | |||
| @@ -262,7 +262,9 @@ static int | |||
| 262 | nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) | 262 | nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) |
| 263 | { | 263 | { |
| 264 | struct kvec *iov = req->rq_rcv_buf.head; | 264 | struct kvec *iov = req->rq_rcv_buf.head; |
| 265 | int status, count, recvd, hdrlen; | 265 | size_t hdrlen; |
| 266 | u32 count, recvd; | ||
| 267 | int status; | ||
| 266 | 268 | ||
| 267 | if ((status = ntohl(*p++))) | 269 | if ((status = ntohl(*p++))) |
| 268 | return -nfs_stat_to_errno(status); | 270 | return -nfs_stat_to_errno(status); |
| @@ -273,7 +275,7 @@ nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) | |||
| 273 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; | 275 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; |
| 274 | if (iov->iov_len < hdrlen) { | 276 | if (iov->iov_len < hdrlen) { |
| 275 | dprintk("NFS: READ reply header overflowed:" | 277 | dprintk("NFS: READ reply header overflowed:" |
| 276 | "length %d > %Zu\n", hdrlen, iov->iov_len); | 278 | "length %Zu > %Zu\n", hdrlen, iov->iov_len); |
| 277 | return -errno_NFSERR_IO; | 279 | return -errno_NFSERR_IO; |
| 278 | } else if (iov->iov_len != hdrlen) { | 280 | } else if (iov->iov_len != hdrlen) { |
| 279 | dprintk("NFS: READ header is short. iovec will be shifted.\n"); | 281 | dprintk("NFS: READ header is short. iovec will be shifted.\n"); |
| @@ -283,11 +285,11 @@ nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) | |||
| 283 | recvd = req->rq_rcv_buf.len - hdrlen; | 285 | recvd = req->rq_rcv_buf.len - hdrlen; |
| 284 | if (count > recvd) { | 286 | if (count > recvd) { |
| 285 | dprintk("NFS: server cheating in read reply: " | 287 | dprintk("NFS: server cheating in read reply: " |
| 286 | "count %d > recvd %d\n", count, recvd); | 288 | "count %u > recvd %u\n", count, recvd); |
| 287 | count = recvd; | 289 | count = recvd; |
| 288 | } | 290 | } |
| 289 | 291 | ||
| 290 | dprintk("RPC: readres OK count %d\n", count); | 292 | dprintk("RPC: readres OK count %u\n", count); |
| 291 | if (count < res->count) | 293 | if (count < res->count) |
| 292 | res->count = count; | 294 | res->count = count; |
| 293 | 295 | ||
| @@ -423,9 +425,10 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
| 423 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; | 425 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; |
| 424 | struct kvec *iov = rcvbuf->head; | 426 | struct kvec *iov = rcvbuf->head; |
| 425 | struct page **page; | 427 | struct page **page; |
| 426 | int hdrlen, recvd; | 428 | size_t hdrlen; |
| 429 | unsigned int pglen, recvd; | ||
| 430 | u32 len; | ||
| 427 | int status, nr; | 431 | int status, nr; |
| 428 | unsigned int len, pglen; | ||
| 429 | __be32 *end, *entry, *kaddr; | 432 | __be32 *end, *entry, *kaddr; |
| 430 | 433 | ||
| 431 | if ((status = ntohl(*p++))) | 434 | if ((status = ntohl(*p++))) |
| @@ -434,7 +437,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
| 434 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; | 437 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; |
| 435 | if (iov->iov_len < hdrlen) { | 438 | if (iov->iov_len < hdrlen) { |
| 436 | dprintk("NFS: READDIR reply header overflowed:" | 439 | dprintk("NFS: READDIR reply header overflowed:" |
| 437 | "length %d > %Zu\n", hdrlen, iov->iov_len); | 440 | "length %Zu > %Zu\n", hdrlen, iov->iov_len); |
| 438 | return -errno_NFSERR_IO; | 441 | return -errno_NFSERR_IO; |
| 439 | } else if (iov->iov_len != hdrlen) { | 442 | } else if (iov->iov_len != hdrlen) { |
| 440 | dprintk("NFS: READDIR header is short. iovec will be shifted.\n"); | 443 | dprintk("NFS: READDIR header is short. iovec will be shifted.\n"); |
| @@ -576,7 +579,8 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
| 576 | { | 579 | { |
| 577 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; | 580 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; |
| 578 | struct kvec *iov = rcvbuf->head; | 581 | struct kvec *iov = rcvbuf->head; |
| 579 | int hdrlen, len, recvd; | 582 | size_t hdrlen; |
| 583 | u32 len, recvd; | ||
| 580 | char *kaddr; | 584 | char *kaddr; |
| 581 | int status; | 585 | int status; |
| 582 | 586 | ||
| @@ -584,14 +588,14 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
| 584 | return -nfs_stat_to_errno(status); | 588 | return -nfs_stat_to_errno(status); |
| 585 | /* Convert length of symlink */ | 589 | /* Convert length of symlink */ |
| 586 | len = ntohl(*p++); | 590 | len = ntohl(*p++); |
| 587 | if (len >= rcvbuf->page_len || len <= 0) { | 591 | if (len >= rcvbuf->page_len) { |
| 588 | dprintk("nfs: server returned giant symlink!\n"); | 592 | dprintk("nfs: server returned giant symlink!\n"); |
| 589 | return -ENAMETOOLONG; | 593 | return -ENAMETOOLONG; |
| 590 | } | 594 | } |
| 591 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; | 595 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; |
| 592 | if (iov->iov_len < hdrlen) { | 596 | if (iov->iov_len < hdrlen) { |
| 593 | dprintk("NFS: READLINK reply header overflowed:" | 597 | dprintk("NFS: READLINK reply header overflowed:" |
| 594 | "length %d > %Zu\n", hdrlen, iov->iov_len); | 598 | "length %Zu > %Zu\n", hdrlen, iov->iov_len); |
| 595 | return -errno_NFSERR_IO; | 599 | return -errno_NFSERR_IO; |
| 596 | } else if (iov->iov_len != hdrlen) { | 600 | } else if (iov->iov_len != hdrlen) { |
| 597 | dprintk("NFS: READLINK header is short. iovec will be shifted.\n"); | 601 | dprintk("NFS: READLINK header is short. iovec will be shifted.\n"); |
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 4cdc2361a669..b353c1a05bfd 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
| @@ -732,16 +732,9 @@ static int nfs3_read_done(struct rpc_task *task, struct nfs_read_data *data) | |||
| 732 | return 0; | 732 | return 0; |
| 733 | } | 733 | } |
| 734 | 734 | ||
| 735 | static void nfs3_proc_read_setup(struct nfs_read_data *data) | 735 | static void nfs3_proc_read_setup(struct nfs_read_data *data, struct rpc_message *msg) |
| 736 | { | 736 | { |
| 737 | struct rpc_message msg = { | 737 | msg->rpc_proc = &nfs3_procedures[NFS3PROC_READ]; |
| 738 | .rpc_proc = &nfs3_procedures[NFS3PROC_READ], | ||
| 739 | .rpc_argp = &data->args, | ||
| 740 | .rpc_resp = &data->res, | ||
| 741 | .rpc_cred = data->cred, | ||
| 742 | }; | ||
| 743 | |||
| 744 | rpc_call_setup(&data->task, &msg, 0); | ||
| 745 | } | 738 | } |
| 746 | 739 | ||
| 747 | static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data) | 740 | static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data) |
| @@ -753,24 +746,9 @@ static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data) | |||
| 753 | return 0; | 746 | return 0; |
| 754 | } | 747 | } |
| 755 | 748 | ||
| 756 | static void nfs3_proc_write_setup(struct nfs_write_data *data, int how) | 749 | static void nfs3_proc_write_setup(struct nfs_write_data *data, struct rpc_message *msg) |
| 757 | { | 750 | { |
| 758 | struct rpc_message msg = { | 751 | msg->rpc_proc = &nfs3_procedures[NFS3PROC_WRITE]; |
| 759 | .rpc_proc = &nfs3_procedures[NFS3PROC_WRITE], | ||
| 760 | .rpc_argp = &data->args, | ||
| 761 | .rpc_resp = &data->res, | ||
| 762 | .rpc_cred = data->cred, | ||
| 763 | }; | ||
| 764 | |||
| 765 | data->args.stable = NFS_UNSTABLE; | ||
| 766 | if (how & FLUSH_STABLE) { | ||
| 767 | data->args.stable = NFS_FILE_SYNC; | ||
| 768 | if (NFS_I(data->inode)->ncommit) | ||
| 769 | data->args.stable = NFS_DATA_SYNC; | ||
| 770 | } | ||
| 771 | |||
| 772 | /* Finalize the task. */ | ||
| 773 | rpc_call_setup(&data->task, &msg, 0); | ||
| 774 | } | 752 | } |
| 775 | 753 | ||
| 776 | static int nfs3_commit_done(struct rpc_task *task, struct nfs_write_data *data) | 754 | static int nfs3_commit_done(struct rpc_task *task, struct nfs_write_data *data) |
| @@ -781,22 +759,17 @@ static int nfs3_commit_done(struct rpc_task *task, struct nfs_write_data *data) | |||
| 781 | return 0; | 759 | return 0; |
| 782 | } | 760 | } |
| 783 | 761 | ||
| 784 | static void nfs3_proc_commit_setup(struct nfs_write_data *data, int how) | 762 | static void nfs3_proc_commit_setup(struct nfs_write_data *data, struct rpc_message *msg) |
| 785 | { | 763 | { |
| 786 | struct rpc_message msg = { | 764 | msg->rpc_proc = &nfs3_procedures[NFS3PROC_COMMIT]; |
| 787 | .rpc_proc = &nfs3_procedures[NFS3PROC_COMMIT], | ||
| 788 | .rpc_argp = &data->args, | ||
| 789 | .rpc_resp = &data->res, | ||
| 790 | .rpc_cred = data->cred, | ||
| 791 | }; | ||
| 792 | |||
| 793 | rpc_call_setup(&data->task, &msg, 0); | ||
| 794 | } | 765 | } |
| 795 | 766 | ||
| 796 | static int | 767 | static int |
| 797 | nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl) | 768 | nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl) |
| 798 | { | 769 | { |
| 799 | return nlmclnt_proc(filp->f_path.dentry->d_inode, cmd, fl); | 770 | struct inode *inode = filp->f_path.dentry->d_inode; |
| 771 | |||
| 772 | return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl); | ||
| 800 | } | 773 | } |
| 801 | 774 | ||
| 802 | const struct nfs_rpc_ops nfs_v3_clientops = { | 775 | const struct nfs_rpc_ops nfs_v3_clientops = { |
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index 616d3267b7e7..3917e2fa4e40 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c | |||
| @@ -506,9 +506,9 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res | |||
| 506 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; | 506 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; |
| 507 | struct kvec *iov = rcvbuf->head; | 507 | struct kvec *iov = rcvbuf->head; |
| 508 | struct page **page; | 508 | struct page **page; |
| 509 | int hdrlen, recvd; | 509 | size_t hdrlen; |
| 510 | u32 len, recvd, pglen; | ||
| 510 | int status, nr; | 511 | int status, nr; |
| 511 | unsigned int len, pglen; | ||
| 512 | __be32 *entry, *end, *kaddr; | 512 | __be32 *entry, *end, *kaddr; |
| 513 | 513 | ||
| 514 | status = ntohl(*p++); | 514 | status = ntohl(*p++); |
| @@ -527,7 +527,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res | |||
| 527 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; | 527 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; |
| 528 | if (iov->iov_len < hdrlen) { | 528 | if (iov->iov_len < hdrlen) { |
| 529 | dprintk("NFS: READDIR reply header overflowed:" | 529 | dprintk("NFS: READDIR reply header overflowed:" |
| 530 | "length %d > %Zu\n", hdrlen, iov->iov_len); | 530 | "length %Zu > %Zu\n", hdrlen, iov->iov_len); |
| 531 | return -errno_NFSERR_IO; | 531 | return -errno_NFSERR_IO; |
| 532 | } else if (iov->iov_len != hdrlen) { | 532 | } else if (iov->iov_len != hdrlen) { |
| 533 | dprintk("NFS: READDIR header is short. iovec will be shifted.\n"); | 533 | dprintk("NFS: READDIR header is short. iovec will be shifted.\n"); |
| @@ -549,7 +549,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res | |||
| 549 | len = ntohl(*p++); /* string length */ | 549 | len = ntohl(*p++); /* string length */ |
| 550 | p += XDR_QUADLEN(len) + 2; /* name + cookie */ | 550 | p += XDR_QUADLEN(len) + 2; /* name + cookie */ |
| 551 | if (len > NFS3_MAXNAMLEN) { | 551 | if (len > NFS3_MAXNAMLEN) { |
| 552 | dprintk("NFS: giant filename in readdir (len %x)!\n", | 552 | dprintk("NFS: giant filename in readdir (len 0x%x)!\n", |
| 553 | len); | 553 | len); |
| 554 | goto err_unmap; | 554 | goto err_unmap; |
| 555 | } | 555 | } |
| @@ -570,7 +570,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res | |||
| 570 | len = ntohl(*p++); | 570 | len = ntohl(*p++); |
| 571 | if (len > NFS3_FHSIZE) { | 571 | if (len > NFS3_FHSIZE) { |
| 572 | dprintk("NFS: giant filehandle in " | 572 | dprintk("NFS: giant filehandle in " |
| 573 | "readdir (len %x)!\n", len); | 573 | "readdir (len 0x%x)!\n", len); |
| 574 | goto err_unmap; | 574 | goto err_unmap; |
| 575 | } | 575 | } |
| 576 | p += XDR_QUADLEN(len); | 576 | p += XDR_QUADLEN(len); |
| @@ -815,7 +815,8 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) | |||
| 815 | { | 815 | { |
| 816 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; | 816 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; |
| 817 | struct kvec *iov = rcvbuf->head; | 817 | struct kvec *iov = rcvbuf->head; |
| 818 | int hdrlen, len, recvd; | 818 | size_t hdrlen; |
| 819 | u32 len, recvd; | ||
| 819 | char *kaddr; | 820 | char *kaddr; |
| 820 | int status; | 821 | int status; |
| 821 | 822 | ||
| @@ -827,7 +828,7 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) | |||
| 827 | 828 | ||
| 828 | /* Convert length of symlink */ | 829 | /* Convert length of symlink */ |
| 829 | len = ntohl(*p++); | 830 | len = ntohl(*p++); |
| 830 | if (len >= rcvbuf->page_len || len <= 0) { | 831 | if (len >= rcvbuf->page_len) { |
| 831 | dprintk("nfs: server returned giant symlink!\n"); | 832 | dprintk("nfs: server returned giant symlink!\n"); |
| 832 | return -ENAMETOOLONG; | 833 | return -ENAMETOOLONG; |
| 833 | } | 834 | } |
| @@ -835,7 +836,7 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) | |||
| 835 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; | 836 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; |
| 836 | if (iov->iov_len < hdrlen) { | 837 | if (iov->iov_len < hdrlen) { |
| 837 | dprintk("NFS: READLINK reply header overflowed:" | 838 | dprintk("NFS: READLINK reply header overflowed:" |
| 838 | "length %d > %Zu\n", hdrlen, iov->iov_len); | 839 | "length %Zu > %Zu\n", hdrlen, iov->iov_len); |
| 839 | return -errno_NFSERR_IO; | 840 | return -errno_NFSERR_IO; |
| 840 | } else if (iov->iov_len != hdrlen) { | 841 | } else if (iov->iov_len != hdrlen) { |
| 841 | dprintk("NFS: READLINK header is short. " | 842 | dprintk("NFS: READLINK header is short. " |
| @@ -863,7 +864,9 @@ static int | |||
| 863 | nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) | 864 | nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) |
| 864 | { | 865 | { |
| 865 | struct kvec *iov = req->rq_rcv_buf.head; | 866 | struct kvec *iov = req->rq_rcv_buf.head; |
| 866 | int status, count, ocount, recvd, hdrlen; | 867 | size_t hdrlen; |
| 868 | u32 count, ocount, recvd; | ||
| 869 | int status; | ||
| 867 | 870 | ||
| 868 | status = ntohl(*p++); | 871 | status = ntohl(*p++); |
| 869 | p = xdr_decode_post_op_attr(p, res->fattr); | 872 | p = xdr_decode_post_op_attr(p, res->fattr); |
| @@ -871,7 +874,7 @@ nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) | |||
| 871 | if (status != 0) | 874 | if (status != 0) |
| 872 | return -nfs_stat_to_errno(status); | 875 | return -nfs_stat_to_errno(status); |
| 873 | 876 | ||
| 874 | /* Decode reply could and EOF flag. NFSv3 is somewhat redundant | 877 | /* Decode reply count and EOF flag. NFSv3 is somewhat redundant |
| 875 | * in that it puts the count both in the res struct and in the | 878 | * in that it puts the count both in the res struct and in the |
| 876 | * opaque data count. */ | 879 | * opaque data count. */ |
| 877 | count = ntohl(*p++); | 880 | count = ntohl(*p++); |
| @@ -886,7 +889,7 @@ nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) | |||
| 886 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; | 889 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; |
| 887 | if (iov->iov_len < hdrlen) { | 890 | if (iov->iov_len < hdrlen) { |
| 888 | dprintk("NFS: READ reply header overflowed:" | 891 | dprintk("NFS: READ reply header overflowed:" |
| 889 | "length %d > %Zu\n", hdrlen, iov->iov_len); | 892 | "length %Zu > %Zu\n", hdrlen, iov->iov_len); |
| 890 | return -errno_NFSERR_IO; | 893 | return -errno_NFSERR_IO; |
| 891 | } else if (iov->iov_len != hdrlen) { | 894 | } else if (iov->iov_len != hdrlen) { |
| 892 | dprintk("NFS: READ header is short. iovec will be shifted.\n"); | 895 | dprintk("NFS: READ header is short. iovec will be shifted.\n"); |
| @@ -896,7 +899,7 @@ nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) | |||
| 896 | recvd = req->rq_rcv_buf.len - hdrlen; | 899 | recvd = req->rq_rcv_buf.len - hdrlen; |
| 897 | if (count > recvd) { | 900 | if (count > recvd) { |
| 898 | dprintk("NFS: server cheating in read reply: " | 901 | dprintk("NFS: server cheating in read reply: " |
| 899 | "count %d > recvd %d\n", count, recvd); | 902 | "count %u > recvd %u\n", count, recvd); |
| 900 | count = recvd; | 903 | count = recvd; |
| 901 | res->eof = 0; | 904 | res->eof = 0; |
| 902 | } | 905 | } |
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index dd5fef20c702..5f9ba41ed5bf 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c | |||
| @@ -114,10 +114,7 @@ static inline int valid_ipaddr4(const char *buf) | |||
| 114 | * nfs_follow_referral - set up mountpoint when hitting a referral on moved error | 114 | * nfs_follow_referral - set up mountpoint when hitting a referral on moved error |
| 115 | * @mnt_parent - mountpoint of parent directory | 115 | * @mnt_parent - mountpoint of parent directory |
| 116 | * @dentry - parent directory | 116 | * @dentry - parent directory |
| 117 | * @fspath - fs path returned in fs_locations | 117 | * @locations - array of NFSv4 server location information |
| 118 | * @mntpath - mount path to new server | ||
| 119 | * @hostname - hostname of new server | ||
| 120 | * @addr - host addr of new server | ||
| 121 | * | 118 | * |
| 122 | */ | 119 | */ |
| 123 | static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | 120 | static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, |
| @@ -131,7 +128,8 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | |||
| 131 | .authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor, | 128 | .authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor, |
| 132 | }; | 129 | }; |
| 133 | char *page = NULL, *page2 = NULL; | 130 | char *page = NULL, *page2 = NULL; |
| 134 | int loc, s, error; | 131 | unsigned int s; |
| 132 | int loc, error; | ||
| 135 | 133 | ||
| 136 | if (locations == NULL || locations->nlocations <= 0) | 134 | if (locations == NULL || locations->nlocations <= 0) |
| 137 | goto out; | 135 | goto out; |
| @@ -174,7 +172,10 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | |||
| 174 | 172 | ||
| 175 | s = 0; | 173 | s = 0; |
| 176 | while (s < location->nservers) { | 174 | while (s < location->nservers) { |
| 177 | struct sockaddr_in addr = {}; | 175 | struct sockaddr_in addr = { |
| 176 | .sin_family = AF_INET, | ||
| 177 | .sin_port = htons(NFS_PORT), | ||
| 178 | }; | ||
| 178 | 179 | ||
| 179 | if (location->servers[s].len <= 0 || | 180 | if (location->servers[s].len <= 0 || |
| 180 | valid_ipaddr4(location->servers[s].data) < 0) { | 181 | valid_ipaddr4(location->servers[s].data) < 0) { |
| @@ -183,10 +184,9 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | |||
| 183 | } | 184 | } |
| 184 | 185 | ||
| 185 | mountdata.hostname = location->servers[s].data; | 186 | mountdata.hostname = location->servers[s].data; |
| 186 | addr.sin_addr.s_addr = in_aton(mountdata.hostname); | 187 | addr.sin_addr.s_addr = in_aton(mountdata.hostname), |
| 187 | addr.sin_family = AF_INET; | 188 | mountdata.addr = (struct sockaddr *)&addr; |
| 188 | addr.sin_port = htons(NFS_PORT); | 189 | mountdata.addrlen = sizeof(addr); |
| 189 | mountdata.addr = &addr; | ||
| 190 | 190 | ||
| 191 | snprintf(page, PAGE_SIZE, "%s:%s", | 191 | snprintf(page, PAGE_SIZE, "%s:%s", |
| 192 | mountdata.hostname, | 192 | mountdata.hostname, |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 9e2e1c7291db..5c189bd57eb2 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
| @@ -210,7 +210,7 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) | |||
| 210 | spin_lock(&dir->i_lock); | 210 | spin_lock(&dir->i_lock); |
| 211 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA; | 211 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA; |
| 212 | if (!cinfo->atomic || cinfo->before != nfsi->change_attr) | 212 | if (!cinfo->atomic || cinfo->before != nfsi->change_attr) |
| 213 | nfsi->cache_change_attribute = jiffies; | 213 | nfs_force_lookup_revalidate(dir); |
| 214 | nfsi->change_attr = cinfo->after; | 214 | nfsi->change_attr = cinfo->after; |
| 215 | spin_unlock(&dir->i_lock); | 215 | spin_unlock(&dir->i_lock); |
| 216 | } | 216 | } |
| @@ -718,19 +718,6 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state | |||
| 718 | return err; | 718 | return err; |
| 719 | } | 719 | } |
| 720 | 720 | ||
| 721 | static void nfs4_open_confirm_prepare(struct rpc_task *task, void *calldata) | ||
| 722 | { | ||
| 723 | struct nfs4_opendata *data = calldata; | ||
| 724 | struct rpc_message msg = { | ||
| 725 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_CONFIRM], | ||
| 726 | .rpc_argp = &data->c_arg, | ||
| 727 | .rpc_resp = &data->c_res, | ||
| 728 | .rpc_cred = data->owner->so_cred, | ||
| 729 | }; | ||
| 730 | data->timestamp = jiffies; | ||
| 731 | rpc_call_setup(task, &msg, 0); | ||
| 732 | } | ||
| 733 | |||
| 734 | static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata) | 721 | static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata) |
| 735 | { | 722 | { |
| 736 | struct nfs4_opendata *data = calldata; | 723 | struct nfs4_opendata *data = calldata; |
| @@ -767,7 +754,6 @@ out_free: | |||
| 767 | } | 754 | } |
| 768 | 755 | ||
| 769 | static const struct rpc_call_ops nfs4_open_confirm_ops = { | 756 | static const struct rpc_call_ops nfs4_open_confirm_ops = { |
| 770 | .rpc_call_prepare = nfs4_open_confirm_prepare, | ||
| 771 | .rpc_call_done = nfs4_open_confirm_done, | 757 | .rpc_call_done = nfs4_open_confirm_done, |
| 772 | .rpc_release = nfs4_open_confirm_release, | 758 | .rpc_release = nfs4_open_confirm_release, |
| 773 | }; | 759 | }; |
| @@ -779,12 +765,26 @@ static int _nfs4_proc_open_confirm(struct nfs4_opendata *data) | |||
| 779 | { | 765 | { |
| 780 | struct nfs_server *server = NFS_SERVER(data->dir->d_inode); | 766 | struct nfs_server *server = NFS_SERVER(data->dir->d_inode); |
| 781 | struct rpc_task *task; | 767 | struct rpc_task *task; |
| 768 | struct rpc_message msg = { | ||
| 769 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_CONFIRM], | ||
| 770 | .rpc_argp = &data->c_arg, | ||
| 771 | .rpc_resp = &data->c_res, | ||
| 772 | .rpc_cred = data->owner->so_cred, | ||
| 773 | }; | ||
| 774 | struct rpc_task_setup task_setup_data = { | ||
| 775 | .rpc_client = server->client, | ||
| 776 | .rpc_message = &msg, | ||
| 777 | .callback_ops = &nfs4_open_confirm_ops, | ||
| 778 | .callback_data = data, | ||
| 779 | .flags = RPC_TASK_ASYNC, | ||
| 780 | }; | ||
| 782 | int status; | 781 | int status; |
| 783 | 782 | ||
| 784 | kref_get(&data->kref); | 783 | kref_get(&data->kref); |
| 785 | data->rpc_done = 0; | 784 | data->rpc_done = 0; |
| 786 | data->rpc_status = 0; | 785 | data->rpc_status = 0; |
| 787 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_confirm_ops, data); | 786 | data->timestamp = jiffies; |
| 787 | task = rpc_run_task(&task_setup_data); | ||
| 788 | if (IS_ERR(task)) | 788 | if (IS_ERR(task)) |
| 789 | return PTR_ERR(task); | 789 | return PTR_ERR(task); |
| 790 | status = nfs4_wait_for_completion_rpc_task(task); | 790 | status = nfs4_wait_for_completion_rpc_task(task); |
| @@ -801,13 +801,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) | |||
| 801 | { | 801 | { |
| 802 | struct nfs4_opendata *data = calldata; | 802 | struct nfs4_opendata *data = calldata; |
| 803 | struct nfs4_state_owner *sp = data->owner; | 803 | struct nfs4_state_owner *sp = data->owner; |
| 804 | struct rpc_message msg = { | 804 | |
| 805 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN], | ||
| 806 | .rpc_argp = &data->o_arg, | ||
| 807 | .rpc_resp = &data->o_res, | ||
| 808 | .rpc_cred = sp->so_cred, | ||
| 809 | }; | ||
| 810 | |||
| 811 | if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0) | 805 | if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0) |
| 812 | return; | 806 | return; |
| 813 | /* | 807 | /* |
| @@ -832,11 +826,11 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) | |||
| 832 | data->o_arg.id = sp->so_owner_id.id; | 826 | data->o_arg.id = sp->so_owner_id.id; |
| 833 | data->o_arg.clientid = sp->so_client->cl_clientid; | 827 | data->o_arg.clientid = sp->so_client->cl_clientid; |
| 834 | if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) { | 828 | if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) { |
| 835 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; | 829 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; |
| 836 | nfs_copy_fh(&data->o_res.fh, data->o_arg.fh); | 830 | nfs_copy_fh(&data->o_res.fh, data->o_arg.fh); |
| 837 | } | 831 | } |
| 838 | data->timestamp = jiffies; | 832 | data->timestamp = jiffies; |
| 839 | rpc_call_setup(task, &msg, 0); | 833 | rpc_call_start(task); |
| 840 | return; | 834 | return; |
| 841 | out_no_action: | 835 | out_no_action: |
| 842 | task->tk_action = NULL; | 836 | task->tk_action = NULL; |
| @@ -908,13 +902,26 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
| 908 | struct nfs_openargs *o_arg = &data->o_arg; | 902 | struct nfs_openargs *o_arg = &data->o_arg; |
| 909 | struct nfs_openres *o_res = &data->o_res; | 903 | struct nfs_openres *o_res = &data->o_res; |
| 910 | struct rpc_task *task; | 904 | struct rpc_task *task; |
| 905 | struct rpc_message msg = { | ||
| 906 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN], | ||
| 907 | .rpc_argp = o_arg, | ||
| 908 | .rpc_resp = o_res, | ||
| 909 | .rpc_cred = data->owner->so_cred, | ||
| 910 | }; | ||
| 911 | struct rpc_task_setup task_setup_data = { | ||
| 912 | .rpc_client = server->client, | ||
| 913 | .rpc_message = &msg, | ||
| 914 | .callback_ops = &nfs4_open_ops, | ||
| 915 | .callback_data = data, | ||
| 916 | .flags = RPC_TASK_ASYNC, | ||
| 917 | }; | ||
| 911 | int status; | 918 | int status; |
| 912 | 919 | ||
| 913 | kref_get(&data->kref); | 920 | kref_get(&data->kref); |
| 914 | data->rpc_done = 0; | 921 | data->rpc_done = 0; |
| 915 | data->rpc_status = 0; | 922 | data->rpc_status = 0; |
| 916 | data->cancelled = 0; | 923 | data->cancelled = 0; |
| 917 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_ops, data); | 924 | task = rpc_run_task(&task_setup_data); |
| 918 | if (IS_ERR(task)) | 925 | if (IS_ERR(task)) |
| 919 | return PTR_ERR(task); | 926 | return PTR_ERR(task); |
| 920 | status = nfs4_wait_for_completion_rpc_task(task); | 927 | status = nfs4_wait_for_completion_rpc_task(task); |
| @@ -1244,12 +1251,6 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
| 1244 | { | 1251 | { |
| 1245 | struct nfs4_closedata *calldata = data; | 1252 | struct nfs4_closedata *calldata = data; |
| 1246 | struct nfs4_state *state = calldata->state; | 1253 | struct nfs4_state *state = calldata->state; |
| 1247 | struct rpc_message msg = { | ||
| 1248 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE], | ||
| 1249 | .rpc_argp = &calldata->arg, | ||
| 1250 | .rpc_resp = &calldata->res, | ||
| 1251 | .rpc_cred = state->owner->so_cred, | ||
| 1252 | }; | ||
| 1253 | int clear_rd, clear_wr, clear_rdwr; | 1254 | int clear_rd, clear_wr, clear_rdwr; |
| 1254 | 1255 | ||
| 1255 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) | 1256 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) |
| @@ -1276,14 +1277,14 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
| 1276 | } | 1277 | } |
| 1277 | nfs_fattr_init(calldata->res.fattr); | 1278 | nfs_fattr_init(calldata->res.fattr); |
| 1278 | if (test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0) { | 1279 | if (test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0) { |
| 1279 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; | 1280 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; |
| 1280 | calldata->arg.open_flags = FMODE_READ; | 1281 | calldata->arg.open_flags = FMODE_READ; |
| 1281 | } else if (test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0) { | 1282 | } else if (test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0) { |
| 1282 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; | 1283 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; |
| 1283 | calldata->arg.open_flags = FMODE_WRITE; | 1284 | calldata->arg.open_flags = FMODE_WRITE; |
| 1284 | } | 1285 | } |
| 1285 | calldata->timestamp = jiffies; | 1286 | calldata->timestamp = jiffies; |
| 1286 | rpc_call_setup(task, &msg, 0); | 1287 | rpc_call_start(task); |
| 1287 | } | 1288 | } |
| 1288 | 1289 | ||
| 1289 | static const struct rpc_call_ops nfs4_close_ops = { | 1290 | static const struct rpc_call_ops nfs4_close_ops = { |
| @@ -1309,6 +1310,16 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
| 1309 | struct nfs4_closedata *calldata; | 1310 | struct nfs4_closedata *calldata; |
| 1310 | struct nfs4_state_owner *sp = state->owner; | 1311 | struct nfs4_state_owner *sp = state->owner; |
| 1311 | struct rpc_task *task; | 1312 | struct rpc_task *task; |
| 1313 | struct rpc_message msg = { | ||
| 1314 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE], | ||
| 1315 | .rpc_cred = state->owner->so_cred, | ||
| 1316 | }; | ||
| 1317 | struct rpc_task_setup task_setup_data = { | ||
| 1318 | .rpc_client = server->client, | ||
| 1319 | .rpc_message = &msg, | ||
| 1320 | .callback_ops = &nfs4_close_ops, | ||
| 1321 | .flags = RPC_TASK_ASYNC, | ||
| 1322 | }; | ||
| 1312 | int status = -ENOMEM; | 1323 | int status = -ENOMEM; |
| 1313 | 1324 | ||
| 1314 | calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); | 1325 | calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); |
| @@ -1328,7 +1339,10 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
| 1328 | calldata->path.mnt = mntget(path->mnt); | 1339 | calldata->path.mnt = mntget(path->mnt); |
| 1329 | calldata->path.dentry = dget(path->dentry); | 1340 | calldata->path.dentry = dget(path->dentry); |
| 1330 | 1341 | ||
| 1331 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_close_ops, calldata); | 1342 | msg.rpc_argp = &calldata->arg, |
| 1343 | msg.rpc_resp = &calldata->res, | ||
| 1344 | task_setup_data.callback_data = calldata; | ||
| 1345 | task = rpc_run_task(&task_setup_data); | ||
| 1332 | if (IS_ERR(task)) | 1346 | if (IS_ERR(task)) |
| 1333 | return PTR_ERR(task); | 1347 | return PTR_ERR(task); |
| 1334 | status = 0; | 1348 | status = 0; |
| @@ -2414,18 +2428,10 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) | |||
| 2414 | return 0; | 2428 | return 0; |
| 2415 | } | 2429 | } |
| 2416 | 2430 | ||
| 2417 | static void nfs4_proc_read_setup(struct nfs_read_data *data) | 2431 | static void nfs4_proc_read_setup(struct nfs_read_data *data, struct rpc_message *msg) |
| 2418 | { | 2432 | { |
| 2419 | struct rpc_message msg = { | ||
| 2420 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ], | ||
| 2421 | .rpc_argp = &data->args, | ||
| 2422 | .rpc_resp = &data->res, | ||
| 2423 | .rpc_cred = data->cred, | ||
| 2424 | }; | ||
| 2425 | |||
| 2426 | data->timestamp = jiffies; | 2433 | data->timestamp = jiffies; |
| 2427 | 2434 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ]; | |
| 2428 | rpc_call_setup(&data->task, &msg, 0); | ||
| 2429 | } | 2435 | } |
| 2430 | 2436 | ||
| 2431 | static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) | 2437 | static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) |
| @@ -2443,33 +2449,15 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) | |||
| 2443 | return 0; | 2449 | return 0; |
| 2444 | } | 2450 | } |
| 2445 | 2451 | ||
| 2446 | static void nfs4_proc_write_setup(struct nfs_write_data *data, int how) | 2452 | static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_message *msg) |
| 2447 | { | 2453 | { |
| 2448 | struct rpc_message msg = { | 2454 | struct nfs_server *server = NFS_SERVER(data->inode); |
| 2449 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE], | 2455 | |
| 2450 | .rpc_argp = &data->args, | ||
| 2451 | .rpc_resp = &data->res, | ||
| 2452 | .rpc_cred = data->cred, | ||
| 2453 | }; | ||
| 2454 | struct inode *inode = data->inode; | ||
| 2455 | struct nfs_server *server = NFS_SERVER(inode); | ||
| 2456 | int stable; | ||
| 2457 | |||
| 2458 | if (how & FLUSH_STABLE) { | ||
| 2459 | if (!NFS_I(inode)->ncommit) | ||
| 2460 | stable = NFS_FILE_SYNC; | ||
| 2461 | else | ||
| 2462 | stable = NFS_DATA_SYNC; | ||
| 2463 | } else | ||
| 2464 | stable = NFS_UNSTABLE; | ||
| 2465 | data->args.stable = stable; | ||
| 2466 | data->args.bitmask = server->attr_bitmask; | 2456 | data->args.bitmask = server->attr_bitmask; |
| 2467 | data->res.server = server; | 2457 | data->res.server = server; |
| 2468 | |||
| 2469 | data->timestamp = jiffies; | 2458 | data->timestamp = jiffies; |
| 2470 | 2459 | ||
| 2471 | /* Finalize the task. */ | 2460 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE]; |
| 2472 | rpc_call_setup(&data->task, &msg, 0); | ||
| 2473 | } | 2461 | } |
| 2474 | 2462 | ||
| 2475 | static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) | 2463 | static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) |
| @@ -2484,20 +2472,13 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) | |||
| 2484 | return 0; | 2472 | return 0; |
| 2485 | } | 2473 | } |
| 2486 | 2474 | ||
| 2487 | static void nfs4_proc_commit_setup(struct nfs_write_data *data, int how) | 2475 | static void nfs4_proc_commit_setup(struct nfs_write_data *data, struct rpc_message *msg) |
| 2488 | { | 2476 | { |
| 2489 | struct rpc_message msg = { | ||
| 2490 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT], | ||
| 2491 | .rpc_argp = &data->args, | ||
| 2492 | .rpc_resp = &data->res, | ||
| 2493 | .rpc_cred = data->cred, | ||
| 2494 | }; | ||
| 2495 | struct nfs_server *server = NFS_SERVER(data->inode); | 2477 | struct nfs_server *server = NFS_SERVER(data->inode); |
| 2496 | 2478 | ||
| 2497 | data->args.bitmask = server->attr_bitmask; | 2479 | data->args.bitmask = server->attr_bitmask; |
| 2498 | data->res.server = server; | 2480 | data->res.server = server; |
| 2499 | 2481 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT]; | |
| 2500 | rpc_call_setup(&data->task, &msg, 0); | ||
| 2501 | } | 2482 | } |
| 2502 | 2483 | ||
| 2503 | /* | 2484 | /* |
| @@ -2910,14 +2891,20 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short po | |||
| 2910 | 2891 | ||
| 2911 | for(;;) { | 2892 | for(;;) { |
| 2912 | setclientid.sc_name_len = scnprintf(setclientid.sc_name, | 2893 | setclientid.sc_name_len = scnprintf(setclientid.sc_name, |
| 2913 | sizeof(setclientid.sc_name), "%s/%u.%u.%u.%u %s %u", | 2894 | sizeof(setclientid.sc_name), "%s/%s %s %s %u", |
| 2914 | clp->cl_ipaddr, NIPQUAD(clp->cl_addr.sin_addr), | 2895 | clp->cl_ipaddr, |
| 2896 | rpc_peeraddr2str(clp->cl_rpcclient, | ||
| 2897 | RPC_DISPLAY_ADDR), | ||
| 2898 | rpc_peeraddr2str(clp->cl_rpcclient, | ||
| 2899 | RPC_DISPLAY_PROTO), | ||
| 2915 | cred->cr_ops->cr_name, | 2900 | cred->cr_ops->cr_name, |
| 2916 | clp->cl_id_uniquifier); | 2901 | clp->cl_id_uniquifier); |
| 2917 | setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, | 2902 | setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, |
| 2918 | sizeof(setclientid.sc_netid), "tcp"); | 2903 | sizeof(setclientid.sc_netid), |
| 2904 | rpc_peeraddr2str(clp->cl_rpcclient, | ||
| 2905 | RPC_DISPLAY_NETID)); | ||
| 2919 | setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr, | 2906 | setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr, |
| 2920 | sizeof(setclientid.sc_uaddr), "%s.%d.%d", | 2907 | sizeof(setclientid.sc_uaddr), "%s.%u.%u", |
| 2921 | clp->cl_ipaddr, port >> 8, port & 255); | 2908 | clp->cl_ipaddr, port >> 8, port & 255); |
| 2922 | 2909 | ||
| 2923 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); | 2910 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); |
| @@ -2981,25 +2968,11 @@ struct nfs4_delegreturndata { | |||
| 2981 | struct nfs4_delegreturnres res; | 2968 | struct nfs4_delegreturnres res; |
| 2982 | struct nfs_fh fh; | 2969 | struct nfs_fh fh; |
| 2983 | nfs4_stateid stateid; | 2970 | nfs4_stateid stateid; |
| 2984 | struct rpc_cred *cred; | ||
| 2985 | unsigned long timestamp; | 2971 | unsigned long timestamp; |
| 2986 | struct nfs_fattr fattr; | 2972 | struct nfs_fattr fattr; |
| 2987 | int rpc_status; | 2973 | int rpc_status; |
| 2988 | }; | 2974 | }; |
| 2989 | 2975 | ||
| 2990 | static void nfs4_delegreturn_prepare(struct rpc_task *task, void *calldata) | ||
| 2991 | { | ||
| 2992 | struct nfs4_delegreturndata *data = calldata; | ||
| 2993 | struct rpc_message msg = { | ||
| 2994 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DELEGRETURN], | ||
| 2995 | .rpc_argp = &data->args, | ||
| 2996 | .rpc_resp = &data->res, | ||
| 2997 | .rpc_cred = data->cred, | ||
| 2998 | }; | ||
| 2999 | nfs_fattr_init(data->res.fattr); | ||
| 3000 | rpc_call_setup(task, &msg, 0); | ||
| 3001 | } | ||
| 3002 | |||
| 3003 | static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) | 2976 | static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) |
| 3004 | { | 2977 | { |
| 3005 | struct nfs4_delegreturndata *data = calldata; | 2978 | struct nfs4_delegreturndata *data = calldata; |
| @@ -3010,24 +2983,30 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) | |||
| 3010 | 2983 | ||
| 3011 | static void nfs4_delegreturn_release(void *calldata) | 2984 | static void nfs4_delegreturn_release(void *calldata) |
| 3012 | { | 2985 | { |
| 3013 | struct nfs4_delegreturndata *data = calldata; | ||
| 3014 | |||
| 3015 | put_rpccred(data->cred); | ||
| 3016 | kfree(calldata); | 2986 | kfree(calldata); |
| 3017 | } | 2987 | } |
| 3018 | 2988 | ||
| 3019 | static const struct rpc_call_ops nfs4_delegreturn_ops = { | 2989 | static const struct rpc_call_ops nfs4_delegreturn_ops = { |
| 3020 | .rpc_call_prepare = nfs4_delegreturn_prepare, | ||
| 3021 | .rpc_call_done = nfs4_delegreturn_done, | 2990 | .rpc_call_done = nfs4_delegreturn_done, |
| 3022 | .rpc_release = nfs4_delegreturn_release, | 2991 | .rpc_release = nfs4_delegreturn_release, |
| 3023 | }; | 2992 | }; |
| 3024 | 2993 | ||
| 3025 | static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid) | 2994 | static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync) |
| 3026 | { | 2995 | { |
| 3027 | struct nfs4_delegreturndata *data; | 2996 | struct nfs4_delegreturndata *data; |
| 3028 | struct nfs_server *server = NFS_SERVER(inode); | 2997 | struct nfs_server *server = NFS_SERVER(inode); |
| 3029 | struct rpc_task *task; | 2998 | struct rpc_task *task; |
| 3030 | int status; | 2999 | struct rpc_message msg = { |
| 3000 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DELEGRETURN], | ||
| 3001 | .rpc_cred = cred, | ||
| 3002 | }; | ||
| 3003 | struct rpc_task_setup task_setup_data = { | ||
| 3004 | .rpc_client = server->client, | ||
| 3005 | .rpc_message = &msg, | ||
| 3006 | .callback_ops = &nfs4_delegreturn_ops, | ||
| 3007 | .flags = RPC_TASK_ASYNC, | ||
| 3008 | }; | ||
| 3009 | int status = 0; | ||
| 3031 | 3010 | ||
| 3032 | data = kmalloc(sizeof(*data), GFP_KERNEL); | 3011 | data = kmalloc(sizeof(*data), GFP_KERNEL); |
| 3033 | if (data == NULL) | 3012 | if (data == NULL) |
| @@ -3039,30 +3018,37 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co | |||
| 3039 | memcpy(&data->stateid, stateid, sizeof(data->stateid)); | 3018 | memcpy(&data->stateid, stateid, sizeof(data->stateid)); |
| 3040 | data->res.fattr = &data->fattr; | 3019 | data->res.fattr = &data->fattr; |
| 3041 | data->res.server = server; | 3020 | data->res.server = server; |
| 3042 | data->cred = get_rpccred(cred); | 3021 | nfs_fattr_init(data->res.fattr); |
| 3043 | data->timestamp = jiffies; | 3022 | data->timestamp = jiffies; |
| 3044 | data->rpc_status = 0; | 3023 | data->rpc_status = 0; |
| 3045 | 3024 | ||
| 3046 | task = rpc_run_task(NFS_CLIENT(inode), RPC_TASK_ASYNC, &nfs4_delegreturn_ops, data); | 3025 | task_setup_data.callback_data = data; |
| 3026 | msg.rpc_argp = &data->args, | ||
| 3027 | msg.rpc_resp = &data->res, | ||
| 3028 | task = rpc_run_task(&task_setup_data); | ||
| 3047 | if (IS_ERR(task)) | 3029 | if (IS_ERR(task)) |
| 3048 | return PTR_ERR(task); | 3030 | return PTR_ERR(task); |
| 3031 | if (!issync) | ||
| 3032 | goto out; | ||
| 3049 | status = nfs4_wait_for_completion_rpc_task(task); | 3033 | status = nfs4_wait_for_completion_rpc_task(task); |
| 3050 | if (status == 0) { | 3034 | if (status != 0) |
| 3051 | status = data->rpc_status; | 3035 | goto out; |
| 3052 | if (status == 0) | 3036 | status = data->rpc_status; |
| 3053 | nfs_refresh_inode(inode, &data->fattr); | 3037 | if (status != 0) |
| 3054 | } | 3038 | goto out; |
| 3039 | nfs_refresh_inode(inode, &data->fattr); | ||
| 3040 | out: | ||
| 3055 | rpc_put_task(task); | 3041 | rpc_put_task(task); |
| 3056 | return status; | 3042 | return status; |
| 3057 | } | 3043 | } |
| 3058 | 3044 | ||
| 3059 | int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid) | 3045 | int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync) |
| 3060 | { | 3046 | { |
| 3061 | struct nfs_server *server = NFS_SERVER(inode); | 3047 | struct nfs_server *server = NFS_SERVER(inode); |
| 3062 | struct nfs4_exception exception = { }; | 3048 | struct nfs4_exception exception = { }; |
| 3063 | int err; | 3049 | int err; |
| 3064 | do { | 3050 | do { |
| 3065 | err = _nfs4_proc_delegreturn(inode, cred, stateid); | 3051 | err = _nfs4_proc_delegreturn(inode, cred, stateid, issync); |
| 3066 | switch (err) { | 3052 | switch (err) { |
| 3067 | case -NFS4ERR_STALE_STATEID: | 3053 | case -NFS4ERR_STALE_STATEID: |
| 3068 | case -NFS4ERR_EXPIRED: | 3054 | case -NFS4ERR_EXPIRED: |
| @@ -3230,12 +3216,6 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
| 3230 | static void nfs4_locku_prepare(struct rpc_task *task, void *data) | 3216 | static void nfs4_locku_prepare(struct rpc_task *task, void *data) |
| 3231 | { | 3217 | { |
| 3232 | struct nfs4_unlockdata *calldata = data; | 3218 | struct nfs4_unlockdata *calldata = data; |
| 3233 | struct rpc_message msg = { | ||
| 3234 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKU], | ||
| 3235 | .rpc_argp = &calldata->arg, | ||
| 3236 | .rpc_resp = &calldata->res, | ||
| 3237 | .rpc_cred = calldata->lsp->ls_state->owner->so_cred, | ||
| 3238 | }; | ||
| 3239 | 3219 | ||
| 3240 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) | 3220 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) |
| 3241 | return; | 3221 | return; |
| @@ -3245,7 +3225,7 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data) | |||
| 3245 | return; | 3225 | return; |
| 3246 | } | 3226 | } |
| 3247 | calldata->timestamp = jiffies; | 3227 | calldata->timestamp = jiffies; |
| 3248 | rpc_call_setup(task, &msg, 0); | 3228 | rpc_call_start(task); |
| 3249 | } | 3229 | } |
| 3250 | 3230 | ||
| 3251 | static const struct rpc_call_ops nfs4_locku_ops = { | 3231 | static const struct rpc_call_ops nfs4_locku_ops = { |
| @@ -3260,6 +3240,16 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl, | |||
| 3260 | struct nfs_seqid *seqid) | 3240 | struct nfs_seqid *seqid) |
| 3261 | { | 3241 | { |
| 3262 | struct nfs4_unlockdata *data; | 3242 | struct nfs4_unlockdata *data; |
| 3243 | struct rpc_message msg = { | ||
| 3244 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKU], | ||
| 3245 | .rpc_cred = ctx->cred, | ||
| 3246 | }; | ||
| 3247 | struct rpc_task_setup task_setup_data = { | ||
| 3248 | .rpc_client = NFS_CLIENT(lsp->ls_state->inode), | ||
| 3249 | .rpc_message = &msg, | ||
| 3250 | .callback_ops = &nfs4_locku_ops, | ||
| 3251 | .flags = RPC_TASK_ASYNC, | ||
| 3252 | }; | ||
| 3263 | 3253 | ||
| 3264 | /* Ensure this is an unlock - when canceling a lock, the | 3254 | /* Ensure this is an unlock - when canceling a lock, the |
| 3265 | * canceled lock is passed in, and it won't be an unlock. | 3255 | * canceled lock is passed in, and it won't be an unlock. |
| @@ -3272,7 +3262,10 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl, | |||
| 3272 | return ERR_PTR(-ENOMEM); | 3262 | return ERR_PTR(-ENOMEM); |
| 3273 | } | 3263 | } |
| 3274 | 3264 | ||
| 3275 | return rpc_run_task(NFS_CLIENT(lsp->ls_state->inode), RPC_TASK_ASYNC, &nfs4_locku_ops, data); | 3265 | msg.rpc_argp = &data->arg, |
| 3266 | msg.rpc_resp = &data->res, | ||
| 3267 | task_setup_data.callback_data = data; | ||
| 3268 | return rpc_run_task(&task_setup_data); | ||
| 3276 | } | 3269 | } |
| 3277 | 3270 | ||
| 3278 | static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) | 3271 | static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) |
| @@ -3331,15 +3324,12 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | |||
| 3331 | 3324 | ||
| 3332 | p->arg.fh = NFS_FH(inode); | 3325 | p->arg.fh = NFS_FH(inode); |
| 3333 | p->arg.fl = &p->fl; | 3326 | p->arg.fl = &p->fl; |
| 3334 | if (!(lsp->ls_seqid.flags & NFS_SEQID_CONFIRMED)) { | 3327 | p->arg.open_seqid = nfs_alloc_seqid(&lsp->ls_state->owner->so_seqid); |
| 3335 | p->arg.open_seqid = nfs_alloc_seqid(&lsp->ls_state->owner->so_seqid); | 3328 | if (p->arg.open_seqid == NULL) |
| 3336 | if (p->arg.open_seqid == NULL) | 3329 | goto out_free; |
| 3337 | goto out_free; | ||
| 3338 | |||
| 3339 | } | ||
| 3340 | p->arg.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid); | 3330 | p->arg.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid); |
| 3341 | if (p->arg.lock_seqid == NULL) | 3331 | if (p->arg.lock_seqid == NULL) |
| 3342 | goto out_free; | 3332 | goto out_free_seqid; |
| 3343 | p->arg.lock_stateid = &lsp->ls_stateid; | 3333 | p->arg.lock_stateid = &lsp->ls_stateid; |
| 3344 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; | 3334 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; |
| 3345 | p->arg.lock_owner.id = lsp->ls_id.id; | 3335 | p->arg.lock_owner.id = lsp->ls_id.id; |
| @@ -3348,9 +3338,9 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | |||
| 3348 | p->ctx = get_nfs_open_context(ctx); | 3338 | p->ctx = get_nfs_open_context(ctx); |
| 3349 | memcpy(&p->fl, fl, sizeof(p->fl)); | 3339 | memcpy(&p->fl, fl, sizeof(p->fl)); |
| 3350 | return p; | 3340 | return p; |
| 3341 | out_free_seqid: | ||
| 3342 | nfs_free_seqid(p->arg.open_seqid); | ||
| 3351 | out_free: | 3343 | out_free: |
| 3352 | if (p->arg.open_seqid != NULL) | ||
| 3353 | nfs_free_seqid(p->arg.open_seqid); | ||
| 3354 | kfree(p); | 3344 | kfree(p); |
| 3355 | return NULL; | 3345 | return NULL; |
| 3356 | } | 3346 | } |
| @@ -3359,31 +3349,20 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) | |||
| 3359 | { | 3349 | { |
| 3360 | struct nfs4_lockdata *data = calldata; | 3350 | struct nfs4_lockdata *data = calldata; |
| 3361 | struct nfs4_state *state = data->lsp->ls_state; | 3351 | struct nfs4_state *state = data->lsp->ls_state; |
| 3362 | struct nfs4_state_owner *sp = state->owner; | ||
| 3363 | struct rpc_message msg = { | ||
| 3364 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCK], | ||
| 3365 | .rpc_argp = &data->arg, | ||
| 3366 | .rpc_resp = &data->res, | ||
| 3367 | .rpc_cred = sp->so_cred, | ||
| 3368 | }; | ||
| 3369 | 3352 | ||
| 3370 | dprintk("%s: begin!\n", __FUNCTION__); | 3353 | dprintk("%s: begin!\n", __FUNCTION__); |
| 3354 | if (nfs_wait_on_sequence(data->arg.lock_seqid, task) != 0) | ||
| 3355 | return; | ||
| 3371 | /* Do we need to do an open_to_lock_owner? */ | 3356 | /* Do we need to do an open_to_lock_owner? */ |
| 3372 | if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) { | 3357 | if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) { |
| 3373 | if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0) | 3358 | if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0) |
| 3374 | return; | 3359 | return; |
| 3375 | data->arg.open_stateid = &state->stateid; | 3360 | data->arg.open_stateid = &state->stateid; |
| 3376 | data->arg.new_lock_owner = 1; | 3361 | data->arg.new_lock_owner = 1; |
| 3377 | /* Retest in case we raced... */ | 3362 | } else |
| 3378 | if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) | 3363 | data->arg.new_lock_owner = 0; |
| 3379 | goto do_rpc; | ||
| 3380 | } | ||
| 3381 | if (nfs_wait_on_sequence(data->arg.lock_seqid, task) != 0) | ||
| 3382 | return; | ||
| 3383 | data->arg.new_lock_owner = 0; | ||
| 3384 | do_rpc: | ||
| 3385 | data->timestamp = jiffies; | 3364 | data->timestamp = jiffies; |
| 3386 | rpc_call_setup(task, &msg, 0); | 3365 | rpc_call_start(task); |
| 3387 | dprintk("%s: done!, ret = %d\n", __FUNCTION__, data->rpc_status); | 3366 | dprintk("%s: done!, ret = %d\n", __FUNCTION__, data->rpc_status); |
| 3388 | } | 3367 | } |
| 3389 | 3368 | ||
| @@ -3419,6 +3398,7 @@ static void nfs4_lock_release(void *calldata) | |||
| 3419 | struct nfs4_lockdata *data = calldata; | 3398 | struct nfs4_lockdata *data = calldata; |
| 3420 | 3399 | ||
| 3421 | dprintk("%s: begin!\n", __FUNCTION__); | 3400 | dprintk("%s: begin!\n", __FUNCTION__); |
| 3401 | nfs_free_seqid(data->arg.open_seqid); | ||
| 3422 | if (data->cancelled != 0) { | 3402 | if (data->cancelled != 0) { |
| 3423 | struct rpc_task *task; | 3403 | struct rpc_task *task; |
| 3424 | task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp, | 3404 | task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp, |
| @@ -3428,8 +3408,6 @@ static void nfs4_lock_release(void *calldata) | |||
| 3428 | dprintk("%s: cancelling lock!\n", __FUNCTION__); | 3408 | dprintk("%s: cancelling lock!\n", __FUNCTION__); |
| 3429 | } else | 3409 | } else |
| 3430 | nfs_free_seqid(data->arg.lock_seqid); | 3410 | nfs_free_seqid(data->arg.lock_seqid); |
| 3431 | if (data->arg.open_seqid != NULL) | ||
| 3432 | nfs_free_seqid(data->arg.open_seqid); | ||
| 3433 | nfs4_put_lock_state(data->lsp); | 3411 | nfs4_put_lock_state(data->lsp); |
| 3434 | put_nfs_open_context(data->ctx); | 3412 | put_nfs_open_context(data->ctx); |
| 3435 | kfree(data); | 3413 | kfree(data); |
| @@ -3446,6 +3424,16 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f | |||
| 3446 | { | 3424 | { |
| 3447 | struct nfs4_lockdata *data; | 3425 | struct nfs4_lockdata *data; |
| 3448 | struct rpc_task *task; | 3426 | struct rpc_task *task; |
| 3427 | struct rpc_message msg = { | ||
| 3428 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCK], | ||
| 3429 | .rpc_cred = state->owner->so_cred, | ||
| 3430 | }; | ||
| 3431 | struct rpc_task_setup task_setup_data = { | ||
| 3432 | .rpc_client = NFS_CLIENT(state->inode), | ||
| 3433 | .rpc_message = &msg, | ||
| 3434 | .callback_ops = &nfs4_lock_ops, | ||
| 3435 | .flags = RPC_TASK_ASYNC, | ||
| 3436 | }; | ||
| 3449 | int ret; | 3437 | int ret; |
| 3450 | 3438 | ||
| 3451 | dprintk("%s: begin!\n", __FUNCTION__); | 3439 | dprintk("%s: begin!\n", __FUNCTION__); |
| @@ -3457,8 +3445,10 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f | |||
| 3457 | data->arg.block = 1; | 3445 | data->arg.block = 1; |
| 3458 | if (reclaim != 0) | 3446 | if (reclaim != 0) |
| 3459 | data->arg.reclaim = 1; | 3447 | data->arg.reclaim = 1; |
| 3460 | task = rpc_run_task(NFS_CLIENT(state->inode), RPC_TASK_ASYNC, | 3448 | msg.rpc_argp = &data->arg, |
| 3461 | &nfs4_lock_ops, data); | 3449 | msg.rpc_resp = &data->res, |
| 3450 | task_setup_data.callback_data = data; | ||
| 3451 | task = rpc_run_task(&task_setup_data); | ||
| 3462 | if (IS_ERR(task)) | 3452 | if (IS_ERR(task)) |
| 3463 | return PTR_ERR(task); | 3453 | return PTR_ERR(task); |
| 3464 | ret = nfs4_wait_for_completion_rpc_task(task); | 3454 | ret = nfs4_wait_for_completion_rpc_task(task); |
| @@ -3631,10 +3621,6 @@ int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf, | |||
| 3631 | if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0) | 3621 | if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0) |
| 3632 | return -EOPNOTSUPP; | 3622 | return -EOPNOTSUPP; |
| 3633 | 3623 | ||
| 3634 | if (!S_ISREG(inode->i_mode) && | ||
| 3635 | (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX)) | ||
| 3636 | return -EPERM; | ||
| 3637 | |||
| 3638 | return nfs4_proc_set_acl(inode, buf, buflen); | 3624 | return nfs4_proc_set_acl(inode, buf, buflen); |
| 3639 | } | 3625 | } |
| 3640 | 3626 | ||
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 5a39c6f78acf..f9c7432471dc 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
| @@ -644,27 +644,26 @@ void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t f | |||
| 644 | 644 | ||
| 645 | struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter) | 645 | struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter) |
| 646 | { | 646 | { |
| 647 | struct rpc_sequence *sequence = counter->sequence; | ||
| 648 | struct nfs_seqid *new; | 647 | struct nfs_seqid *new; |
| 649 | 648 | ||
| 650 | new = kmalloc(sizeof(*new), GFP_KERNEL); | 649 | new = kmalloc(sizeof(*new), GFP_KERNEL); |
| 651 | if (new != NULL) { | 650 | if (new != NULL) { |
| 652 | new->sequence = counter; | 651 | new->sequence = counter; |
| 653 | spin_lock(&sequence->lock); | 652 | INIT_LIST_HEAD(&new->list); |
| 654 | list_add_tail(&new->list, &sequence->list); | ||
| 655 | spin_unlock(&sequence->lock); | ||
| 656 | } | 653 | } |
| 657 | return new; | 654 | return new; |
| 658 | } | 655 | } |
| 659 | 656 | ||
| 660 | void nfs_free_seqid(struct nfs_seqid *seqid) | 657 | void nfs_free_seqid(struct nfs_seqid *seqid) |
| 661 | { | 658 | { |
| 662 | struct rpc_sequence *sequence = seqid->sequence->sequence; | 659 | if (!list_empty(&seqid->list)) { |
| 660 | struct rpc_sequence *sequence = seqid->sequence->sequence; | ||
| 663 | 661 | ||
| 664 | spin_lock(&sequence->lock); | 662 | spin_lock(&sequence->lock); |
| 665 | list_del(&seqid->list); | 663 | list_del(&seqid->list); |
| 666 | spin_unlock(&sequence->lock); | 664 | spin_unlock(&sequence->lock); |
| 667 | rpc_wake_up(&sequence->wait); | 665 | rpc_wake_up(&sequence->wait); |
| 666 | } | ||
| 668 | kfree(seqid); | 667 | kfree(seqid); |
| 669 | } | 668 | } |
| 670 | 669 | ||
| @@ -675,6 +674,7 @@ void nfs_free_seqid(struct nfs_seqid *seqid) | |||
| 675 | */ | 674 | */ |
| 676 | static void nfs_increment_seqid(int status, struct nfs_seqid *seqid) | 675 | static void nfs_increment_seqid(int status, struct nfs_seqid *seqid) |
| 677 | { | 676 | { |
| 677 | BUG_ON(list_first_entry(&seqid->sequence->sequence->list, struct nfs_seqid, list) != seqid); | ||
| 678 | switch (status) { | 678 | switch (status) { |
| 679 | case 0: | 679 | case 0: |
| 680 | break; | 680 | break; |
| @@ -726,15 +726,15 @@ int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task) | |||
| 726 | struct rpc_sequence *sequence = seqid->sequence->sequence; | 726 | struct rpc_sequence *sequence = seqid->sequence->sequence; |
| 727 | int status = 0; | 727 | int status = 0; |
| 728 | 728 | ||
| 729 | if (sequence->list.next == &seqid->list) | ||
| 730 | goto out; | ||
| 731 | spin_lock(&sequence->lock); | 729 | spin_lock(&sequence->lock); |
| 732 | if (sequence->list.next != &seqid->list) { | 730 | if (list_empty(&seqid->list)) |
| 733 | rpc_sleep_on(&sequence->wait, task, NULL, NULL); | 731 | list_add_tail(&seqid->list, &sequence->list); |
| 734 | status = -EAGAIN; | 732 | if (list_first_entry(&sequence->list, struct nfs_seqid, list) == seqid) |
| 735 | } | 733 | goto unlock; |
| 734 | rpc_sleep_on(&sequence->wait, task, NULL, NULL); | ||
| 735 | status = -EAGAIN; | ||
| 736 | unlock: | ||
| 736 | spin_unlock(&sequence->lock); | 737 | spin_unlock(&sequence->lock); |
| 737 | out: | ||
| 738 | return status; | 738 | return status; |
| 739 | } | 739 | } |
| 740 | 740 | ||
| @@ -758,8 +758,9 @@ static void nfs4_recover_state(struct nfs_client *clp) | |||
| 758 | 758 | ||
| 759 | __module_get(THIS_MODULE); | 759 | __module_get(THIS_MODULE); |
| 760 | atomic_inc(&clp->cl_count); | 760 | atomic_inc(&clp->cl_count); |
| 761 | task = kthread_run(reclaimer, clp, "%u.%u.%u.%u-reclaim", | 761 | task = kthread_run(reclaimer, clp, "%s-reclaim", |
| 762 | NIPQUAD(clp->cl_addr.sin_addr)); | 762 | rpc_peeraddr2str(clp->cl_rpcclient, |
| 763 | RPC_DISPLAY_ADDR)); | ||
| 763 | if (!IS_ERR(task)) | 764 | if (!IS_ERR(task)) |
| 764 | return; | 765 | return; |
| 765 | nfs4_clear_recover_bit(clp); | 766 | nfs4_clear_recover_bit(clp); |
| @@ -970,8 +971,8 @@ out: | |||
| 970 | module_put_and_exit(0); | 971 | module_put_and_exit(0); |
| 971 | return 0; | 972 | return 0; |
| 972 | out_error: | 973 | out_error: |
| 973 | printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u with error %d\n", | 974 | printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %s" |
| 974 | NIPQUAD(clp->cl_addr.sin_addr), -status); | 975 | " with error %d\n", clp->cl_hostname, -status); |
| 975 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 976 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); |
| 976 | goto out; | 977 | goto out; |
| 977 | } | 978 | } |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 51dd3804866f..db1ed9c46ede 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
| @@ -116,10 +116,12 @@ static int nfs4_stat_to_errno(int); | |||
| 116 | #define decode_renew_maxsz (op_decode_hdr_maxsz) | 116 | #define decode_renew_maxsz (op_decode_hdr_maxsz) |
| 117 | #define encode_setclientid_maxsz \ | 117 | #define encode_setclientid_maxsz \ |
| 118 | (op_encode_hdr_maxsz + \ | 118 | (op_encode_hdr_maxsz + \ |
| 119 | 4 /*server->ip_addr*/ + \ | 119 | XDR_QUADLEN(NFS4_VERIFIER_SIZE) + \ |
| 120 | 1 /*Netid*/ + \ | 120 | XDR_QUADLEN(NFS4_SETCLIENTID_NAMELEN) + \ |
| 121 | 6 /*uaddr*/ + \ | 121 | 1 /* sc_prog */ + \ |
| 122 | 6 + (NFS4_VERIFIER_SIZE >> 2)) | 122 | XDR_QUADLEN(RPCBIND_MAXNETIDLEN) + \ |
| 123 | XDR_QUADLEN(RPCBIND_MAXUADDRLEN) + \ | ||
| 124 | 1) /* sc_cb_ident */ | ||
| 123 | #define decode_setclientid_maxsz \ | 125 | #define decode_setclientid_maxsz \ |
| 124 | (op_decode_hdr_maxsz + \ | 126 | (op_decode_hdr_maxsz + \ |
| 125 | 2 + \ | 127 | 2 + \ |
| @@ -2515,14 +2517,12 @@ static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uin | |||
| 2515 | 2517 | ||
| 2516 | static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path) | 2518 | static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path) |
| 2517 | { | 2519 | { |
| 2518 | int n; | 2520 | u32 n; |
| 2519 | __be32 *p; | 2521 | __be32 *p; |
| 2520 | int status = 0; | 2522 | int status = 0; |
| 2521 | 2523 | ||
| 2522 | READ_BUF(4); | 2524 | READ_BUF(4); |
| 2523 | READ32(n); | 2525 | READ32(n); |
| 2524 | if (n < 0) | ||
| 2525 | goto out_eio; | ||
| 2526 | if (n == 0) | 2526 | if (n == 0) |
| 2527 | goto root_path; | 2527 | goto root_path; |
| 2528 | dprintk("path "); | 2528 | dprintk("path "); |
| @@ -2579,13 +2579,11 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st | |||
| 2579 | goto out_eio; | 2579 | goto out_eio; |
| 2580 | res->nlocations = 0; | 2580 | res->nlocations = 0; |
| 2581 | while (res->nlocations < n) { | 2581 | while (res->nlocations < n) { |
| 2582 | int m; | 2582 | u32 m; |
| 2583 | struct nfs4_fs_location *loc = &res->locations[res->nlocations]; | 2583 | struct nfs4_fs_location *loc = &res->locations[res->nlocations]; |
| 2584 | 2584 | ||
| 2585 | READ_BUF(4); | 2585 | READ_BUF(4); |
| 2586 | READ32(m); | 2586 | READ32(m); |
| 2587 | if (m <= 0) | ||
| 2588 | goto out_eio; | ||
| 2589 | 2587 | ||
| 2590 | loc->nservers = 0; | 2588 | loc->nservers = 0; |
| 2591 | dprintk("%s: servers ", __FUNCTION__); | 2589 | dprintk("%s: servers ", __FUNCTION__); |
| @@ -2598,8 +2596,12 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st | |||
| 2598 | if (loc->nservers < NFS4_FS_LOCATION_MAXSERVERS) | 2596 | if (loc->nservers < NFS4_FS_LOCATION_MAXSERVERS) |
| 2599 | loc->nservers++; | 2597 | loc->nservers++; |
| 2600 | else { | 2598 | else { |
| 2601 | int i; | 2599 | unsigned int i; |
| 2602 | dprintk("%s: using first %d of %d servers returned for location %d\n", __FUNCTION__, NFS4_FS_LOCATION_MAXSERVERS, m, res->nlocations); | 2600 | dprintk("%s: using first %u of %u servers " |
| 2601 | "returned for location %u\n", | ||
| 2602 | __FUNCTION__, | ||
| 2603 | NFS4_FS_LOCATION_MAXSERVERS, | ||
| 2604 | m, res->nlocations); | ||
| 2603 | for (i = loc->nservers; i < m; i++) { | 2605 | for (i = loc->nservers; i < m; i++) { |
| 2604 | unsigned int len; | 2606 | unsigned int len; |
| 2605 | char *data; | 2607 | char *data; |
| @@ -3476,10 +3478,11 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
| 3476 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; | 3478 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; |
| 3477 | struct page *page = *rcvbuf->pages; | 3479 | struct page *page = *rcvbuf->pages; |
| 3478 | struct kvec *iov = rcvbuf->head; | 3480 | struct kvec *iov = rcvbuf->head; |
| 3479 | unsigned int nr, pglen = rcvbuf->page_len; | 3481 | size_t hdrlen; |
| 3482 | u32 recvd, pglen = rcvbuf->page_len; | ||
| 3480 | __be32 *end, *entry, *p, *kaddr; | 3483 | __be32 *end, *entry, *p, *kaddr; |
| 3481 | uint32_t len, attrlen, xlen; | 3484 | unsigned int nr; |
| 3482 | int hdrlen, recvd, status; | 3485 | int status; |
| 3483 | 3486 | ||
| 3484 | status = decode_op_hdr(xdr, OP_READDIR); | 3487 | status = decode_op_hdr(xdr, OP_READDIR); |
| 3485 | if (status) | 3488 | if (status) |
| @@ -3503,6 +3506,7 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
| 3503 | end = p + ((pglen + readdir->pgbase) >> 2); | 3506 | end = p + ((pglen + readdir->pgbase) >> 2); |
| 3504 | entry = p; | 3507 | entry = p; |
| 3505 | for (nr = 0; *p++; nr++) { | 3508 | for (nr = 0; *p++; nr++) { |
| 3509 | u32 len, attrlen, xlen; | ||
| 3506 | if (end - p < 3) | 3510 | if (end - p < 3) |
| 3507 | goto short_pkt; | 3511 | goto short_pkt; |
| 3508 | dprintk("cookie = %Lu, ", *((unsigned long long *)p)); | 3512 | dprintk("cookie = %Lu, ", *((unsigned long long *)p)); |
| @@ -3551,7 +3555,8 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) | |||
| 3551 | { | 3555 | { |
| 3552 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; | 3556 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; |
| 3553 | struct kvec *iov = rcvbuf->head; | 3557 | struct kvec *iov = rcvbuf->head; |
| 3554 | int hdrlen, len, recvd; | 3558 | size_t hdrlen; |
| 3559 | u32 len, recvd; | ||
| 3555 | __be32 *p; | 3560 | __be32 *p; |
| 3556 | char *kaddr; | 3561 | char *kaddr; |
| 3557 | int status; | 3562 | int status; |
| @@ -3646,7 +3651,8 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, | |||
| 3646 | if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U))) | 3651 | if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U))) |
| 3647 | return -EIO; | 3652 | return -EIO; |
| 3648 | if (likely(bitmap[0] & FATTR4_WORD0_ACL)) { | 3653 | if (likely(bitmap[0] & FATTR4_WORD0_ACL)) { |
| 3649 | int hdrlen, recvd; | 3654 | size_t hdrlen; |
| 3655 | u32 recvd; | ||
| 3650 | 3656 | ||
| 3651 | /* We ignore &savep and don't do consistency checks on | 3657 | /* We ignore &savep and don't do consistency checks on |
| 3652 | * the attr length. Let userspace figure it out.... */ | 3658 | * the attr length. Let userspace figure it out.... */ |
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 345bb9b4765b..3b3dbb94393d 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
| @@ -111,13 +111,14 @@ void nfs_unlock_request(struct nfs_page *req) | |||
| 111 | * nfs_set_page_tag_locked - Tag a request as locked | 111 | * nfs_set_page_tag_locked - Tag a request as locked |
| 112 | * @req: | 112 | * @req: |
| 113 | */ | 113 | */ |
| 114 | static int nfs_set_page_tag_locked(struct nfs_page *req) | 114 | int nfs_set_page_tag_locked(struct nfs_page *req) |
| 115 | { | 115 | { |
| 116 | struct nfs_inode *nfsi = NFS_I(req->wb_context->path.dentry->d_inode); | 116 | struct nfs_inode *nfsi = NFS_I(req->wb_context->path.dentry->d_inode); |
| 117 | 117 | ||
| 118 | if (!nfs_lock_request(req)) | 118 | if (!nfs_lock_request_dontget(req)) |
| 119 | return 0; | 119 | return 0; |
| 120 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); | 120 | if (req->wb_page != NULL) |
| 121 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); | ||
| 121 | return 1; | 122 | return 1; |
| 122 | } | 123 | } |
| 123 | 124 | ||
| @@ -132,9 +133,10 @@ void nfs_clear_page_tag_locked(struct nfs_page *req) | |||
| 132 | if (req->wb_page != NULL) { | 133 | if (req->wb_page != NULL) { |
| 133 | spin_lock(&inode->i_lock); | 134 | spin_lock(&inode->i_lock); |
| 134 | radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); | 135 | radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); |
| 136 | nfs_unlock_request(req); | ||
| 135 | spin_unlock(&inode->i_lock); | 137 | spin_unlock(&inode->i_lock); |
| 136 | } | 138 | } else |
| 137 | nfs_unlock_request(req); | 139 | nfs_unlock_request(req); |
| 138 | } | 140 | } |
| 139 | 141 | ||
| 140 | /** | 142 | /** |
| @@ -421,6 +423,7 @@ int nfs_scan_list(struct nfs_inode *nfsi, | |||
| 421 | goto out; | 423 | goto out; |
| 422 | idx_start = req->wb_index + 1; | 424 | idx_start = req->wb_index + 1; |
| 423 | if (nfs_set_page_tag_locked(req)) { | 425 | if (nfs_set_page_tag_locked(req)) { |
| 426 | kref_get(&req->wb_kref); | ||
| 424 | nfs_list_remove_request(req); | 427 | nfs_list_remove_request(req); |
| 425 | radix_tree_tag_clear(&nfsi->nfs_page_tree, | 428 | radix_tree_tag_clear(&nfsi->nfs_page_tree, |
| 426 | req->wb_index, tag); | 429 | req->wb_index, tag); |
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index 4f80d88e9fee..5ccf7faee19c 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c | |||
| @@ -565,16 +565,9 @@ static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data) | |||
| 565 | return 0; | 565 | return 0; |
| 566 | } | 566 | } |
| 567 | 567 | ||
| 568 | static void nfs_proc_read_setup(struct nfs_read_data *data) | 568 | static void nfs_proc_read_setup(struct nfs_read_data *data, struct rpc_message *msg) |
| 569 | { | 569 | { |
| 570 | struct rpc_message msg = { | 570 | msg->rpc_proc = &nfs_procedures[NFSPROC_READ]; |
| 571 | .rpc_proc = &nfs_procedures[NFSPROC_READ], | ||
| 572 | .rpc_argp = &data->args, | ||
| 573 | .rpc_resp = &data->res, | ||
| 574 | .rpc_cred = data->cred, | ||
| 575 | }; | ||
| 576 | |||
| 577 | rpc_call_setup(&data->task, &msg, 0); | ||
| 578 | } | 571 | } |
| 579 | 572 | ||
| 580 | static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data) | 573 | static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data) |
| @@ -584,24 +577,15 @@ static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data) | |||
| 584 | return 0; | 577 | return 0; |
| 585 | } | 578 | } |
| 586 | 579 | ||
| 587 | static void nfs_proc_write_setup(struct nfs_write_data *data, int how) | 580 | static void nfs_proc_write_setup(struct nfs_write_data *data, struct rpc_message *msg) |
| 588 | { | 581 | { |
| 589 | struct rpc_message msg = { | ||
| 590 | .rpc_proc = &nfs_procedures[NFSPROC_WRITE], | ||
| 591 | .rpc_argp = &data->args, | ||
| 592 | .rpc_resp = &data->res, | ||
| 593 | .rpc_cred = data->cred, | ||
| 594 | }; | ||
| 595 | |||
| 596 | /* Note: NFSv2 ignores @stable and always uses NFS_FILE_SYNC */ | 582 | /* Note: NFSv2 ignores @stable and always uses NFS_FILE_SYNC */ |
| 597 | data->args.stable = NFS_FILE_SYNC; | 583 | data->args.stable = NFS_FILE_SYNC; |
| 598 | 584 | msg->rpc_proc = &nfs_procedures[NFSPROC_WRITE]; | |
| 599 | /* Finalize the task. */ | ||
| 600 | rpc_call_setup(&data->task, &msg, 0); | ||
| 601 | } | 585 | } |
| 602 | 586 | ||
| 603 | static void | 587 | static void |
| 604 | nfs_proc_commit_setup(struct nfs_write_data *data, int how) | 588 | nfs_proc_commit_setup(struct nfs_write_data *data, struct rpc_message *msg) |
| 605 | { | 589 | { |
| 606 | BUG(); | 590 | BUG(); |
| 607 | } | 591 | } |
| @@ -609,7 +593,9 @@ nfs_proc_commit_setup(struct nfs_write_data *data, int how) | |||
| 609 | static int | 593 | static int |
| 610 | nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl) | 594 | nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl) |
| 611 | { | 595 | { |
| 612 | return nlmclnt_proc(filp->f_path.dentry->d_inode, cmd, fl); | 596 | struct inode *inode = filp->f_path.dentry->d_inode; |
| 597 | |||
| 598 | return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl); | ||
| 613 | } | 599 | } |
| 614 | 600 | ||
| 615 | 601 | ||
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 4587a86adaac..8fd6dfbe1bc3 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
| @@ -160,12 +160,26 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | |||
| 160 | const struct rpc_call_ops *call_ops, | 160 | const struct rpc_call_ops *call_ops, |
| 161 | unsigned int count, unsigned int offset) | 161 | unsigned int count, unsigned int offset) |
| 162 | { | 162 | { |
| 163 | struct inode *inode; | 163 | struct inode *inode = req->wb_context->path.dentry->d_inode; |
| 164 | int flags; | 164 | int swap_flags = IS_SWAPFILE(inode) ? NFS_RPC_SWAPFLAGS : 0; |
| 165 | struct rpc_task *task; | ||
| 166 | struct rpc_message msg = { | ||
| 167 | .rpc_argp = &data->args, | ||
| 168 | .rpc_resp = &data->res, | ||
| 169 | .rpc_cred = req->wb_context->cred, | ||
| 170 | }; | ||
| 171 | struct rpc_task_setup task_setup_data = { | ||
| 172 | .task = &data->task, | ||
| 173 | .rpc_client = NFS_CLIENT(inode), | ||
| 174 | .rpc_message = &msg, | ||
| 175 | .callback_ops = call_ops, | ||
| 176 | .callback_data = data, | ||
| 177 | .flags = RPC_TASK_ASYNC | swap_flags, | ||
| 178 | }; | ||
| 165 | 179 | ||
| 166 | data->req = req; | 180 | data->req = req; |
| 167 | data->inode = inode = req->wb_context->path.dentry->d_inode; | 181 | data->inode = inode; |
| 168 | data->cred = req->wb_context->cred; | 182 | data->cred = msg.rpc_cred; |
| 169 | 183 | ||
| 170 | data->args.fh = NFS_FH(inode); | 184 | data->args.fh = NFS_FH(inode); |
| 171 | data->args.offset = req_offset(req) + offset; | 185 | data->args.offset = req_offset(req) + offset; |
| @@ -180,11 +194,7 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | |||
| 180 | nfs_fattr_init(&data->fattr); | 194 | nfs_fattr_init(&data->fattr); |
| 181 | 195 | ||
| 182 | /* Set up the initial task struct. */ | 196 | /* Set up the initial task struct. */ |
| 183 | flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); | 197 | NFS_PROTO(inode)->read_setup(data, &msg); |
| 184 | rpc_init_task(&data->task, NFS_CLIENT(inode), flags, call_ops, data); | ||
| 185 | NFS_PROTO(inode)->read_setup(data); | ||
| 186 | |||
| 187 | data->task.tk_cookie = (unsigned long)inode; | ||
| 188 | 198 | ||
| 189 | dprintk("NFS: %5u initiated read call (req %s/%Ld, %u bytes @ offset %Lu)\n", | 199 | dprintk("NFS: %5u initiated read call (req %s/%Ld, %u bytes @ offset %Lu)\n", |
| 190 | data->task.tk_pid, | 200 | data->task.tk_pid, |
| @@ -192,6 +202,10 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | |||
| 192 | (long long)NFS_FILEID(inode), | 202 | (long long)NFS_FILEID(inode), |
| 193 | count, | 203 | count, |
| 194 | (unsigned long long)data->args.offset); | 204 | (unsigned long long)data->args.offset); |
| 205 | |||
| 206 | task = rpc_run_task(&task_setup_data); | ||
| 207 | if (!IS_ERR(task)) | ||
| 208 | rpc_put_task(task); | ||
| 195 | } | 209 | } |
| 196 | 210 | ||
| 197 | static void | 211 | static void |
| @@ -208,19 +222,6 @@ nfs_async_read_error(struct list_head *head) | |||
| 208 | } | 222 | } |
| 209 | 223 | ||
| 210 | /* | 224 | /* |
| 211 | * Start an async read operation | ||
| 212 | */ | ||
| 213 | static void nfs_execute_read(struct nfs_read_data *data) | ||
| 214 | { | ||
| 215 | struct rpc_clnt *clnt = NFS_CLIENT(data->inode); | ||
| 216 | sigset_t oldset; | ||
| 217 | |||
| 218 | rpc_clnt_sigmask(clnt, &oldset); | ||
| 219 | rpc_execute(&data->task); | ||
| 220 | rpc_clnt_sigunmask(clnt, &oldset); | ||
| 221 | } | ||
| 222 | |||
| 223 | /* | ||
| 224 | * Generate multiple requests to fill a single page. | 225 | * Generate multiple requests to fill a single page. |
| 225 | * | 226 | * |
| 226 | * We optimize to reduce the number of read operations on the wire. If we | 227 | * We optimize to reduce the number of read operations on the wire. If we |
| @@ -274,7 +275,6 @@ static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigne | |||
| 274 | rsize, offset); | 275 | rsize, offset); |
| 275 | offset += rsize; | 276 | offset += rsize; |
| 276 | nbytes -= rsize; | 277 | nbytes -= rsize; |
| 277 | nfs_execute_read(data); | ||
| 278 | } while (nbytes != 0); | 278 | } while (nbytes != 0); |
| 279 | 279 | ||
| 280 | return 0; | 280 | return 0; |
| @@ -312,8 +312,6 @@ static int nfs_pagein_one(struct inode *inode, struct list_head *head, unsigned | |||
| 312 | req = nfs_list_entry(data->pages.next); | 312 | req = nfs_list_entry(data->pages.next); |
| 313 | 313 | ||
| 314 | nfs_read_rpcsetup(req, data, &nfs_read_full_ops, count, 0); | 314 | nfs_read_rpcsetup(req, data, &nfs_read_full_ops, count, 0); |
| 315 | |||
| 316 | nfs_execute_read(data); | ||
| 317 | return 0; | 315 | return 0; |
| 318 | out_bad: | 316 | out_bad: |
| 319 | nfs_async_read_error(head); | 317 | nfs_async_read_error(head); |
| @@ -338,7 +336,7 @@ int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) | |||
| 338 | nfs_add_stats(data->inode, NFSIOS_SERVERREADBYTES, data->res.count); | 336 | nfs_add_stats(data->inode, NFSIOS_SERVERREADBYTES, data->res.count); |
| 339 | 337 | ||
| 340 | if (task->tk_status == -ESTALE) { | 338 | if (task->tk_status == -ESTALE) { |
| 341 | set_bit(NFS_INO_STALE, &NFS_FLAGS(data->inode)); | 339 | set_bit(NFS_INO_STALE, &NFS_I(data->inode)->flags); |
| 342 | nfs_mark_for_revalidate(data->inode); | 340 | nfs_mark_for_revalidate(data->inode); |
| 343 | } | 341 | } |
| 344 | return 0; | 342 | return 0; |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 0b0c72a072ff..22c49c02897d 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
| @@ -45,6 +45,8 @@ | |||
| 45 | #include <linux/nfs_idmap.h> | 45 | #include <linux/nfs_idmap.h> |
| 46 | #include <linux/vfs.h> | 46 | #include <linux/vfs.h> |
| 47 | #include <linux/inet.h> | 47 | #include <linux/inet.h> |
| 48 | #include <linux/in6.h> | ||
| 49 | #include <net/ipv6.h> | ||
| 48 | #include <linux/nfs_xdr.h> | 50 | #include <linux/nfs_xdr.h> |
| 49 | #include <linux/magic.h> | 51 | #include <linux/magic.h> |
| 50 | #include <linux/parser.h> | 52 | #include <linux/parser.h> |
| @@ -83,11 +85,11 @@ enum { | |||
| 83 | Opt_actimeo, | 85 | Opt_actimeo, |
| 84 | Opt_namelen, | 86 | Opt_namelen, |
| 85 | Opt_mountport, | 87 | Opt_mountport, |
| 86 | Opt_mountprog, Opt_mountvers, | 88 | Opt_mountvers, |
| 87 | Opt_nfsprog, Opt_nfsvers, | 89 | Opt_nfsvers, |
| 88 | 90 | ||
| 89 | /* Mount options that take string arguments */ | 91 | /* Mount options that take string arguments */ |
| 90 | Opt_sec, Opt_proto, Opt_mountproto, | 92 | Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost, |
| 91 | Opt_addr, Opt_mountaddr, Opt_clientaddr, | 93 | Opt_addr, Opt_mountaddr, Opt_clientaddr, |
| 92 | 94 | ||
| 93 | /* Mount options that are ignored */ | 95 | /* Mount options that are ignored */ |
| @@ -137,9 +139,7 @@ static match_table_t nfs_mount_option_tokens = { | |||
| 137 | { Opt_userspace, "retry=%u" }, | 139 | { Opt_userspace, "retry=%u" }, |
| 138 | { Opt_namelen, "namlen=%u" }, | 140 | { Opt_namelen, "namlen=%u" }, |
| 139 | { Opt_mountport, "mountport=%u" }, | 141 | { Opt_mountport, "mountport=%u" }, |
| 140 | { Opt_mountprog, "mountprog=%u" }, | ||
| 141 | { Opt_mountvers, "mountvers=%u" }, | 142 | { Opt_mountvers, "mountvers=%u" }, |
| 142 | { Opt_nfsprog, "nfsprog=%u" }, | ||
| 143 | { Opt_nfsvers, "nfsvers=%u" }, | 143 | { Opt_nfsvers, "nfsvers=%u" }, |
| 144 | { Opt_nfsvers, "vers=%u" }, | 144 | { Opt_nfsvers, "vers=%u" }, |
| 145 | 145 | ||
| @@ -148,7 +148,7 @@ static match_table_t nfs_mount_option_tokens = { | |||
| 148 | { Opt_mountproto, "mountproto=%s" }, | 148 | { Opt_mountproto, "mountproto=%s" }, |
| 149 | { Opt_addr, "addr=%s" }, | 149 | { Opt_addr, "addr=%s" }, |
| 150 | { Opt_clientaddr, "clientaddr=%s" }, | 150 | { Opt_clientaddr, "clientaddr=%s" }, |
| 151 | { Opt_userspace, "mounthost=%s" }, | 151 | { Opt_mounthost, "mounthost=%s" }, |
| 152 | { Opt_mountaddr, "mountaddr=%s" }, | 152 | { Opt_mountaddr, "mountaddr=%s" }, |
| 153 | 153 | ||
| 154 | { Opt_err, NULL } | 154 | { Opt_err, NULL } |
| @@ -202,6 +202,7 @@ static int nfs_get_sb(struct file_system_type *, int, const char *, void *, stru | |||
| 202 | static int nfs_xdev_get_sb(struct file_system_type *fs_type, | 202 | static int nfs_xdev_get_sb(struct file_system_type *fs_type, |
| 203 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 203 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
| 204 | static void nfs_kill_super(struct super_block *); | 204 | static void nfs_kill_super(struct super_block *); |
| 205 | static void nfs_put_super(struct super_block *); | ||
| 205 | 206 | ||
| 206 | static struct file_system_type nfs_fs_type = { | 207 | static struct file_system_type nfs_fs_type = { |
| 207 | .owner = THIS_MODULE, | 208 | .owner = THIS_MODULE, |
| @@ -223,6 +224,7 @@ static const struct super_operations nfs_sops = { | |||
| 223 | .alloc_inode = nfs_alloc_inode, | 224 | .alloc_inode = nfs_alloc_inode, |
| 224 | .destroy_inode = nfs_destroy_inode, | 225 | .destroy_inode = nfs_destroy_inode, |
| 225 | .write_inode = nfs_write_inode, | 226 | .write_inode = nfs_write_inode, |
| 227 | .put_super = nfs_put_super, | ||
| 226 | .statfs = nfs_statfs, | 228 | .statfs = nfs_statfs, |
| 227 | .clear_inode = nfs_clear_inode, | 229 | .clear_inode = nfs_clear_inode, |
| 228 | .umount_begin = nfs_umount_begin, | 230 | .umount_begin = nfs_umount_begin, |
| @@ -325,6 +327,28 @@ void __exit unregister_nfs_fs(void) | |||
| 325 | unregister_filesystem(&nfs_fs_type); | 327 | unregister_filesystem(&nfs_fs_type); |
| 326 | } | 328 | } |
| 327 | 329 | ||
| 330 | void nfs_sb_active(struct nfs_server *server) | ||
| 331 | { | ||
| 332 | atomic_inc(&server->active); | ||
| 333 | } | ||
| 334 | |||
| 335 | void nfs_sb_deactive(struct nfs_server *server) | ||
| 336 | { | ||
| 337 | if (atomic_dec_and_test(&server->active)) | ||
| 338 | wake_up(&server->active_wq); | ||
| 339 | } | ||
| 340 | |||
| 341 | static void nfs_put_super(struct super_block *sb) | ||
| 342 | { | ||
| 343 | struct nfs_server *server = NFS_SB(sb); | ||
| 344 | /* | ||
| 345 | * Make sure there are no outstanding ops to this server. | ||
| 346 | * If so, wait for them to finish before allowing the | ||
| 347 | * unmount to continue. | ||
| 348 | */ | ||
| 349 | wait_event(server->active_wq, atomic_read(&server->active) == 0); | ||
| 350 | } | ||
| 351 | |||
| 328 | /* | 352 | /* |
| 329 | * Deliver file system statistics to userspace | 353 | * Deliver file system statistics to userspace |
| 330 | */ | 354 | */ |
| @@ -455,8 +479,8 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
| 455 | } | 479 | } |
| 456 | seq_printf(m, ",proto=%s", | 480 | seq_printf(m, ",proto=%s", |
| 457 | rpc_peeraddr2str(nfss->client, RPC_DISPLAY_PROTO)); | 481 | rpc_peeraddr2str(nfss->client, RPC_DISPLAY_PROTO)); |
| 458 | seq_printf(m, ",timeo=%lu", 10U * clp->retrans_timeo / HZ); | 482 | seq_printf(m, ",timeo=%lu", 10U * nfss->client->cl_timeout->to_initval / HZ); |
| 459 | seq_printf(m, ",retrans=%u", clp->retrans_count); | 483 | seq_printf(m, ",retrans=%u", nfss->client->cl_timeout->to_retries); |
| 460 | seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor)); | 484 | seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor)); |
| 461 | } | 485 | } |
| 462 | 486 | ||
| @@ -469,8 +493,9 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
| 469 | 493 | ||
| 470 | nfs_show_mount_options(m, nfss, 0); | 494 | nfs_show_mount_options(m, nfss, 0); |
| 471 | 495 | ||
| 472 | seq_printf(m, ",addr="NIPQUAD_FMT, | 496 | seq_printf(m, ",addr=%s", |
| 473 | NIPQUAD(nfss->nfs_client->cl_addr.sin_addr)); | 497 | rpc_peeraddr2str(nfss->nfs_client->cl_rpcclient, |
| 498 | RPC_DISPLAY_ADDR)); | ||
| 474 | 499 | ||
| 475 | return 0; | 500 | return 0; |
| 476 | } | 501 | } |
| @@ -507,7 +532,7 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt) | |||
| 507 | seq_printf(m, ",namelen=%d", nfss->namelen); | 532 | seq_printf(m, ",namelen=%d", nfss->namelen); |
| 508 | 533 | ||
| 509 | #ifdef CONFIG_NFS_V4 | 534 | #ifdef CONFIG_NFS_V4 |
| 510 | if (nfss->nfs_client->cl_nfsversion == 4) { | 535 | if (nfss->nfs_client->rpc_ops->version == 4) { |
| 511 | seq_printf(m, "\n\tnfsv4:\t"); | 536 | seq_printf(m, "\n\tnfsv4:\t"); |
| 512 | seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]); | 537 | seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]); |
| 513 | seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]); | 538 | seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]); |
| @@ -575,16 +600,40 @@ static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags) | |||
| 575 | } | 600 | } |
| 576 | 601 | ||
| 577 | /* | 602 | /* |
| 578 | * Sanity-check a server address provided by the mount command | 603 | * Set the port number in an address. Be agnostic about the address family. |
| 604 | */ | ||
| 605 | static void nfs_set_port(struct sockaddr *sap, unsigned short port) | ||
| 606 | { | ||
| 607 | switch (sap->sa_family) { | ||
| 608 | case AF_INET: { | ||
| 609 | struct sockaddr_in *ap = (struct sockaddr_in *)sap; | ||
| 610 | ap->sin_port = htons(port); | ||
| 611 | break; | ||
| 612 | } | ||
| 613 | case AF_INET6: { | ||
| 614 | struct sockaddr_in6 *ap = (struct sockaddr_in6 *)sap; | ||
| 615 | ap->sin6_port = htons(port); | ||
| 616 | break; | ||
| 617 | } | ||
| 618 | } | ||
| 619 | } | ||
| 620 | |||
| 621 | /* | ||
| 622 | * Sanity-check a server address provided by the mount command. | ||
| 623 | * | ||
| 624 | * Address family must be initialized, and address must not be | ||
| 625 | * the ANY address for that family. | ||
| 579 | */ | 626 | */ |
| 580 | static int nfs_verify_server_address(struct sockaddr *addr) | 627 | static int nfs_verify_server_address(struct sockaddr *addr) |
| 581 | { | 628 | { |
| 582 | switch (addr->sa_family) { | 629 | switch (addr->sa_family) { |
| 583 | case AF_INET: { | 630 | case AF_INET: { |
| 584 | struct sockaddr_in *sa = (struct sockaddr_in *) addr; | 631 | struct sockaddr_in *sa = (struct sockaddr_in *)addr; |
| 585 | if (sa->sin_addr.s_addr != INADDR_ANY) | 632 | return sa->sin_addr.s_addr != INADDR_ANY; |
| 586 | return 1; | 633 | } |
| 587 | break; | 634 | case AF_INET6: { |
| 635 | struct in6_addr *sa = &((struct sockaddr_in6 *)addr)->sin6_addr; | ||
| 636 | return !ipv6_addr_any(sa); | ||
| 588 | } | 637 | } |
| 589 | } | 638 | } |
| 590 | 639 | ||
| @@ -592,6 +641,40 @@ static int nfs_verify_server_address(struct sockaddr *addr) | |||
| 592 | } | 641 | } |
| 593 | 642 | ||
| 594 | /* | 643 | /* |
| 644 | * Parse string addresses passed in via a mount option, | ||
| 645 | * and construct a sockaddr based on the result. | ||
| 646 | * | ||
| 647 | * If address parsing fails, set the sockaddr's address | ||
| 648 | * family to AF_UNSPEC to force nfs_verify_server_address() | ||
| 649 | * to punt the mount. | ||
| 650 | */ | ||
| 651 | static void nfs_parse_server_address(char *value, | ||
| 652 | struct sockaddr *sap, | ||
| 653 | size_t *len) | ||
| 654 | { | ||
| 655 | if (strchr(value, ':')) { | ||
| 656 | struct sockaddr_in6 *ap = (struct sockaddr_in6 *)sap; | ||
| 657 | u8 *addr = (u8 *)&ap->sin6_addr.in6_u; | ||
| 658 | |||
| 659 | ap->sin6_family = AF_INET6; | ||
| 660 | *len = sizeof(*ap); | ||
| 661 | if (in6_pton(value, -1, addr, '\0', NULL)) | ||
| 662 | return; | ||
| 663 | } else { | ||
| 664 | struct sockaddr_in *ap = (struct sockaddr_in *)sap; | ||
| 665 | u8 *addr = (u8 *)&ap->sin_addr.s_addr; | ||
| 666 | |||
| 667 | ap->sin_family = AF_INET; | ||
| 668 | *len = sizeof(*ap); | ||
| 669 | if (in4_pton(value, -1, addr, '\0', NULL)) | ||
| 670 | return; | ||
| 671 | } | ||
| 672 | |||
| 673 | sap->sa_family = AF_UNSPEC; | ||
| 674 | *len = 0; | ||
| 675 | } | ||
| 676 | |||
| 677 | /* | ||
| 595 | * Error-check and convert a string of mount options from user space into | 678 | * Error-check and convert a string of mount options from user space into |
| 596 | * a data structure | 679 | * a data structure |
| 597 | */ | 680 | */ |
| @@ -599,6 +682,7 @@ static int nfs_parse_mount_options(char *raw, | |||
| 599 | struct nfs_parsed_mount_data *mnt) | 682 | struct nfs_parsed_mount_data *mnt) |
| 600 | { | 683 | { |
| 601 | char *p, *string; | 684 | char *p, *string; |
| 685 | unsigned short port = 0; | ||
| 602 | 686 | ||
| 603 | if (!raw) { | 687 | if (!raw) { |
| 604 | dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); | 688 | dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); |
| @@ -701,7 +785,7 @@ static int nfs_parse_mount_options(char *raw, | |||
| 701 | return 0; | 785 | return 0; |
| 702 | if (option < 0 || option > 65535) | 786 | if (option < 0 || option > 65535) |
| 703 | return 0; | 787 | return 0; |
| 704 | mnt->nfs_server.address.sin_port = htons(option); | 788 | port = option; |
| 705 | break; | 789 | break; |
| 706 | case Opt_rsize: | 790 | case Opt_rsize: |
| 707 | if (match_int(args, &mnt->rsize)) | 791 | if (match_int(args, &mnt->rsize)) |
| @@ -763,13 +847,6 @@ static int nfs_parse_mount_options(char *raw, | |||
| 763 | return 0; | 847 | return 0; |
| 764 | mnt->mount_server.port = option; | 848 | mnt->mount_server.port = option; |
| 765 | break; | 849 | break; |
| 766 | case Opt_mountprog: | ||
| 767 | if (match_int(args, &option)) | ||
| 768 | return 0; | ||
| 769 | if (option < 0) | ||
| 770 | return 0; | ||
| 771 | mnt->mount_server.program = option; | ||
| 772 | break; | ||
| 773 | case Opt_mountvers: | 850 | case Opt_mountvers: |
| 774 | if (match_int(args, &option)) | 851 | if (match_int(args, &option)) |
| 775 | return 0; | 852 | return 0; |
| @@ -777,13 +854,6 @@ static int nfs_parse_mount_options(char *raw, | |||
| 777 | return 0; | 854 | return 0; |
| 778 | mnt->mount_server.version = option; | 855 | mnt->mount_server.version = option; |
| 779 | break; | 856 | break; |
| 780 | case Opt_nfsprog: | ||
| 781 | if (match_int(args, &option)) | ||
| 782 | return 0; | ||
| 783 | if (option < 0) | ||
| 784 | return 0; | ||
| 785 | mnt->nfs_server.program = option; | ||
| 786 | break; | ||
| 787 | case Opt_nfsvers: | 857 | case Opt_nfsvers: |
| 788 | if (match_int(args, &option)) | 858 | if (match_int(args, &option)) |
| 789 | return 0; | 859 | return 0; |
| @@ -927,24 +997,32 @@ static int nfs_parse_mount_options(char *raw, | |||
| 927 | string = match_strdup(args); | 997 | string = match_strdup(args); |
| 928 | if (string == NULL) | 998 | if (string == NULL) |
| 929 | goto out_nomem; | 999 | goto out_nomem; |
| 930 | mnt->nfs_server.address.sin_family = AF_INET; | 1000 | nfs_parse_server_address(string, (struct sockaddr *) |
| 931 | mnt->nfs_server.address.sin_addr.s_addr = | 1001 | &mnt->nfs_server.address, |
| 932 | in_aton(string); | 1002 | &mnt->nfs_server.addrlen); |
| 933 | kfree(string); | 1003 | kfree(string); |
| 934 | break; | 1004 | break; |
| 935 | case Opt_clientaddr: | 1005 | case Opt_clientaddr: |
| 936 | string = match_strdup(args); | 1006 | string = match_strdup(args); |
| 937 | if (string == NULL) | 1007 | if (string == NULL) |
| 938 | goto out_nomem; | 1008 | goto out_nomem; |
| 1009 | kfree(mnt->client_address); | ||
| 939 | mnt->client_address = string; | 1010 | mnt->client_address = string; |
| 940 | break; | 1011 | break; |
| 1012 | case Opt_mounthost: | ||
| 1013 | string = match_strdup(args); | ||
| 1014 | if (string == NULL) | ||
| 1015 | goto out_nomem; | ||
| 1016 | kfree(mnt->mount_server.hostname); | ||
| 1017 | mnt->mount_server.hostname = string; | ||
| 1018 | break; | ||
| 941 | case Opt_mountaddr: | 1019 | case Opt_mountaddr: |
| 942 | string = match_strdup(args); | 1020 | string = match_strdup(args); |
| 943 | if (string == NULL) | 1021 | if (string == NULL) |
| 944 | goto out_nomem; | 1022 | goto out_nomem; |
| 945 | mnt->mount_server.address.sin_family = AF_INET; | 1023 | nfs_parse_server_address(string, (struct sockaddr *) |
| 946 | mnt->mount_server.address.sin_addr.s_addr = | 1024 | &mnt->mount_server.address, |
| 947 | in_aton(string); | 1025 | &mnt->mount_server.addrlen); |
| 948 | kfree(string); | 1026 | kfree(string); |
| 949 | break; | 1027 | break; |
| 950 | 1028 | ||
| @@ -957,6 +1035,8 @@ static int nfs_parse_mount_options(char *raw, | |||
| 957 | } | 1035 | } |
| 958 | } | 1036 | } |
| 959 | 1037 | ||
| 1038 | nfs_set_port((struct sockaddr *)&mnt->nfs_server.address, port); | ||
| 1039 | |||
| 960 | return 1; | 1040 | return 1; |
| 961 | 1041 | ||
| 962 | out_nomem: | 1042 | out_nomem: |
| @@ -987,7 +1067,8 @@ out_unknown: | |||
| 987 | static int nfs_try_mount(struct nfs_parsed_mount_data *args, | 1067 | static int nfs_try_mount(struct nfs_parsed_mount_data *args, |
| 988 | struct nfs_fh *root_fh) | 1068 | struct nfs_fh *root_fh) |
| 989 | { | 1069 | { |
| 990 | struct sockaddr_in sin; | 1070 | struct sockaddr *sap = (struct sockaddr *)&args->mount_server.address; |
| 1071 | char *hostname; | ||
| 991 | int status; | 1072 | int status; |
| 992 | 1073 | ||
| 993 | if (args->mount_server.version == 0) { | 1074 | if (args->mount_server.version == 0) { |
| @@ -997,25 +1078,32 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, | |||
| 997 | args->mount_server.version = NFS_MNT_VERSION; | 1078 | args->mount_server.version = NFS_MNT_VERSION; |
| 998 | } | 1079 | } |
| 999 | 1080 | ||
| 1081 | if (args->mount_server.hostname) | ||
| 1082 | hostname = args->mount_server.hostname; | ||
| 1083 | else | ||
| 1084 | hostname = args->nfs_server.hostname; | ||
| 1085 | |||
| 1000 | /* | 1086 | /* |
| 1001 | * Construct the mount server's address. | 1087 | * Construct the mount server's address. |
| 1002 | */ | 1088 | */ |
| 1003 | if (args->mount_server.address.sin_addr.s_addr != INADDR_ANY) | 1089 | if (args->mount_server.address.ss_family == AF_UNSPEC) { |
| 1004 | sin = args->mount_server.address; | 1090 | memcpy(sap, &args->nfs_server.address, |
| 1005 | else | 1091 | args->nfs_server.addrlen); |
| 1006 | sin = args->nfs_server.address; | 1092 | args->mount_server.addrlen = args->nfs_server.addrlen; |
| 1093 | } | ||
| 1094 | |||
| 1007 | /* | 1095 | /* |
| 1008 | * autobind will be used if mount_server.port == 0 | 1096 | * autobind will be used if mount_server.port == 0 |
| 1009 | */ | 1097 | */ |
| 1010 | sin.sin_port = htons(args->mount_server.port); | 1098 | nfs_set_port(sap, args->mount_server.port); |
| 1011 | 1099 | ||
| 1012 | /* | 1100 | /* |
| 1013 | * Now ask the mount server to map our export path | 1101 | * Now ask the mount server to map our export path |
| 1014 | * to a file handle. | 1102 | * to a file handle. |
| 1015 | */ | 1103 | */ |
| 1016 | status = nfs_mount((struct sockaddr *) &sin, | 1104 | status = nfs_mount(sap, |
| 1017 | sizeof(sin), | 1105 | args->mount_server.addrlen, |
| 1018 | args->nfs_server.hostname, | 1106 | hostname, |
| 1019 | args->nfs_server.export_path, | 1107 | args->nfs_server.export_path, |
| 1020 | args->mount_server.version, | 1108 | args->mount_server.version, |
| 1021 | args->mount_server.protocol, | 1109 | args->mount_server.protocol, |
| @@ -1023,8 +1111,8 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, | |||
| 1023 | if (status == 0) | 1111 | if (status == 0) |
| 1024 | return 0; | 1112 | return 0; |
| 1025 | 1113 | ||
| 1026 | dfprintk(MOUNT, "NFS: unable to mount server " NIPQUAD_FMT | 1114 | dfprintk(MOUNT, "NFS: unable to mount server %s, error %d", |
| 1027 | ", error %d\n", NIPQUAD(sin.sin_addr.s_addr), status); | 1115 | hostname, status); |
| 1028 | return status; | 1116 | return status; |
| 1029 | } | 1117 | } |
| 1030 | 1118 | ||
| @@ -1043,9 +1131,6 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, | |||
| 1043 | * | 1131 | * |
| 1044 | * + breaking back: trying proto=udp after proto=tcp, v2 after v3, | 1132 | * + breaking back: trying proto=udp after proto=tcp, v2 after v3, |
| 1045 | * mountproto=tcp after mountproto=udp, and so on | 1133 | * mountproto=tcp after mountproto=udp, and so on |
| 1046 | * | ||
| 1047 | * XXX: as far as I can tell, changing the NFS program number is not | ||
| 1048 | * supported in the NFS client. | ||
| 1049 | */ | 1134 | */ |
| 1050 | static int nfs_validate_mount_data(void *options, | 1135 | static int nfs_validate_mount_data(void *options, |
| 1051 | struct nfs_parsed_mount_data *args, | 1136 | struct nfs_parsed_mount_data *args, |
| @@ -1069,9 +1154,7 @@ static int nfs_validate_mount_data(void *options, | |||
| 1069 | args->acdirmin = 30; | 1154 | args->acdirmin = 30; |
| 1070 | args->acdirmax = 60; | 1155 | args->acdirmax = 60; |
| 1071 | args->mount_server.protocol = XPRT_TRANSPORT_UDP; | 1156 | args->mount_server.protocol = XPRT_TRANSPORT_UDP; |
| 1072 | args->mount_server.program = NFS_MNT_PROGRAM; | ||
| 1073 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 1157 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; |
| 1074 | args->nfs_server.program = NFS_PROGRAM; | ||
| 1075 | 1158 | ||
| 1076 | switch (data->version) { | 1159 | switch (data->version) { |
| 1077 | case 1: | 1160 | case 1: |
| @@ -1102,9 +1185,6 @@ static int nfs_validate_mount_data(void *options, | |||
| 1102 | memset(mntfh->data + mntfh->size, 0, | 1185 | memset(mntfh->data + mntfh->size, 0, |
| 1103 | sizeof(mntfh->data) - mntfh->size); | 1186 | sizeof(mntfh->data) - mntfh->size); |
| 1104 | 1187 | ||
| 1105 | if (!nfs_verify_server_address((struct sockaddr *) &data->addr)) | ||
| 1106 | goto out_no_address; | ||
| 1107 | |||
| 1108 | /* | 1188 | /* |
| 1109 | * Translate to nfs_parsed_mount_data, which nfs_fill_super | 1189 | * Translate to nfs_parsed_mount_data, which nfs_fill_super |
| 1110 | * can deal with. | 1190 | * can deal with. |
| @@ -1119,7 +1199,14 @@ static int nfs_validate_mount_data(void *options, | |||
| 1119 | args->acregmax = data->acregmax; | 1199 | args->acregmax = data->acregmax; |
| 1120 | args->acdirmin = data->acdirmin; | 1200 | args->acdirmin = data->acdirmin; |
| 1121 | args->acdirmax = data->acdirmax; | 1201 | args->acdirmax = data->acdirmax; |
| 1122 | args->nfs_server.address = data->addr; | 1202 | |
| 1203 | memcpy(&args->nfs_server.address, &data->addr, | ||
| 1204 | sizeof(data->addr)); | ||
| 1205 | args->nfs_server.addrlen = sizeof(data->addr); | ||
| 1206 | if (!nfs_verify_server_address((struct sockaddr *) | ||
| 1207 | &args->nfs_server.address)) | ||
| 1208 | goto out_no_address; | ||
| 1209 | |||
| 1123 | if (!(data->flags & NFS_MOUNT_TCP)) | 1210 | if (!(data->flags & NFS_MOUNT_TCP)) |
| 1124 | args->nfs_server.protocol = XPRT_TRANSPORT_UDP; | 1211 | args->nfs_server.protocol = XPRT_TRANSPORT_UDP; |
| 1125 | /* N.B. caller will free nfs_server.hostname in all cases */ | 1212 | /* N.B. caller will free nfs_server.hostname in all cases */ |
| @@ -1322,15 +1409,50 @@ static int nfs_set_super(struct super_block *s, void *data) | |||
| 1322 | return ret; | 1409 | return ret; |
| 1323 | } | 1410 | } |
| 1324 | 1411 | ||
| 1412 | static int nfs_compare_super_address(struct nfs_server *server1, | ||
| 1413 | struct nfs_server *server2) | ||
| 1414 | { | ||
| 1415 | struct sockaddr *sap1, *sap2; | ||
| 1416 | |||
| 1417 | sap1 = (struct sockaddr *)&server1->nfs_client->cl_addr; | ||
| 1418 | sap2 = (struct sockaddr *)&server2->nfs_client->cl_addr; | ||
| 1419 | |||
| 1420 | if (sap1->sa_family != sap2->sa_family) | ||
| 1421 | return 0; | ||
| 1422 | |||
| 1423 | switch (sap1->sa_family) { | ||
| 1424 | case AF_INET: { | ||
| 1425 | struct sockaddr_in *sin1 = (struct sockaddr_in *)sap1; | ||
| 1426 | struct sockaddr_in *sin2 = (struct sockaddr_in *)sap2; | ||
| 1427 | if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) | ||
| 1428 | return 0; | ||
| 1429 | if (sin1->sin_port != sin2->sin_port) | ||
| 1430 | return 0; | ||
| 1431 | break; | ||
| 1432 | } | ||
| 1433 | case AF_INET6: { | ||
| 1434 | struct sockaddr_in6 *sin1 = (struct sockaddr_in6 *)sap1; | ||
| 1435 | struct sockaddr_in6 *sin2 = (struct sockaddr_in6 *)sap2; | ||
| 1436 | if (!ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr)) | ||
| 1437 | return 0; | ||
| 1438 | if (sin1->sin6_port != sin2->sin6_port) | ||
| 1439 | return 0; | ||
| 1440 | break; | ||
| 1441 | } | ||
| 1442 | default: | ||
| 1443 | return 0; | ||
| 1444 | } | ||
| 1445 | |||
| 1446 | return 1; | ||
| 1447 | } | ||
| 1448 | |||
| 1325 | static int nfs_compare_super(struct super_block *sb, void *data) | 1449 | static int nfs_compare_super(struct super_block *sb, void *data) |
| 1326 | { | 1450 | { |
| 1327 | struct nfs_sb_mountdata *sb_mntdata = data; | 1451 | struct nfs_sb_mountdata *sb_mntdata = data; |
| 1328 | struct nfs_server *server = sb_mntdata->server, *old = NFS_SB(sb); | 1452 | struct nfs_server *server = sb_mntdata->server, *old = NFS_SB(sb); |
| 1329 | int mntflags = sb_mntdata->mntflags; | 1453 | int mntflags = sb_mntdata->mntflags; |
| 1330 | 1454 | ||
| 1331 | if (memcmp(&old->nfs_client->cl_addr, | 1455 | if (!nfs_compare_super_address(old, server)) |
| 1332 | &server->nfs_client->cl_addr, | ||
| 1333 | sizeof(old->nfs_client->cl_addr)) != 0) | ||
| 1334 | return 0; | 1456 | return 0; |
| 1335 | /* Note: NFS_MOUNT_UNSHARED == NFS4_MOUNT_UNSHARED */ | 1457 | /* Note: NFS_MOUNT_UNSHARED == NFS4_MOUNT_UNSHARED */ |
| 1336 | if (old->flags & NFS_MOUNT_UNSHARED) | 1458 | if (old->flags & NFS_MOUNT_UNSHARED) |
| @@ -1400,6 +1522,7 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
| 1400 | 1522 | ||
| 1401 | out: | 1523 | out: |
| 1402 | kfree(data.nfs_server.hostname); | 1524 | kfree(data.nfs_server.hostname); |
| 1525 | kfree(data.mount_server.hostname); | ||
| 1403 | return error; | 1526 | return error; |
| 1404 | 1527 | ||
| 1405 | out_err_nosb: | 1528 | out_err_nosb: |
| @@ -1528,12 +1651,35 @@ static void nfs4_fill_super(struct super_block *sb) | |||
| 1528 | } | 1651 | } |
| 1529 | 1652 | ||
| 1530 | /* | 1653 | /* |
| 1654 | * If the user didn't specify a port, set the port number to | ||
| 1655 | * the NFS version 4 default port. | ||
| 1656 | */ | ||
| 1657 | static void nfs4_default_port(struct sockaddr *sap) | ||
| 1658 | { | ||
| 1659 | switch (sap->sa_family) { | ||
| 1660 | case AF_INET: { | ||
| 1661 | struct sockaddr_in *ap = (struct sockaddr_in *)sap; | ||
| 1662 | if (ap->sin_port == 0) | ||
| 1663 | ap->sin_port = htons(NFS_PORT); | ||
| 1664 | break; | ||
| 1665 | } | ||
| 1666 | case AF_INET6: { | ||
| 1667 | struct sockaddr_in6 *ap = (struct sockaddr_in6 *)sap; | ||
| 1668 | if (ap->sin6_port == 0) | ||
| 1669 | ap->sin6_port = htons(NFS_PORT); | ||
| 1670 | break; | ||
| 1671 | } | ||
| 1672 | } | ||
| 1673 | } | ||
| 1674 | |||
| 1675 | /* | ||
| 1531 | * Validate NFSv4 mount options | 1676 | * Validate NFSv4 mount options |
| 1532 | */ | 1677 | */ |
| 1533 | static int nfs4_validate_mount_data(void *options, | 1678 | static int nfs4_validate_mount_data(void *options, |
| 1534 | struct nfs_parsed_mount_data *args, | 1679 | struct nfs_parsed_mount_data *args, |
| 1535 | const char *dev_name) | 1680 | const char *dev_name) |
| 1536 | { | 1681 | { |
| 1682 | struct sockaddr_in *ap; | ||
| 1537 | struct nfs4_mount_data *data = (struct nfs4_mount_data *)options; | 1683 | struct nfs4_mount_data *data = (struct nfs4_mount_data *)options; |
| 1538 | char *c; | 1684 | char *c; |
| 1539 | 1685 | ||
| @@ -1554,18 +1700,21 @@ static int nfs4_validate_mount_data(void *options, | |||
| 1554 | 1700 | ||
| 1555 | switch (data->version) { | 1701 | switch (data->version) { |
| 1556 | case 1: | 1702 | case 1: |
| 1557 | if (data->host_addrlen != sizeof(args->nfs_server.address)) | 1703 | ap = (struct sockaddr_in *)&args->nfs_server.address; |
| 1704 | if (data->host_addrlen > sizeof(args->nfs_server.address)) | ||
| 1558 | goto out_no_address; | 1705 | goto out_no_address; |
| 1559 | if (copy_from_user(&args->nfs_server.address, | 1706 | if (data->host_addrlen == 0) |
| 1560 | data->host_addr, | 1707 | goto out_no_address; |
| 1561 | sizeof(args->nfs_server.address))) | 1708 | args->nfs_server.addrlen = data->host_addrlen; |
| 1709 | if (copy_from_user(ap, data->host_addr, data->host_addrlen)) | ||
| 1562 | return -EFAULT; | 1710 | return -EFAULT; |
| 1563 | if (args->nfs_server.address.sin_port == 0) | ||
| 1564 | args->nfs_server.address.sin_port = htons(NFS_PORT); | ||
| 1565 | if (!nfs_verify_server_address((struct sockaddr *) | 1711 | if (!nfs_verify_server_address((struct sockaddr *) |
| 1566 | &args->nfs_server.address)) | 1712 | &args->nfs_server.address)) |
| 1567 | goto out_no_address; | 1713 | goto out_no_address; |
| 1568 | 1714 | ||
| 1715 | nfs4_default_port((struct sockaddr *) | ||
| 1716 | &args->nfs_server.address); | ||
| 1717 | |||
| 1569 | switch (data->auth_flavourlen) { | 1718 | switch (data->auth_flavourlen) { |
| 1570 | case 0: | 1719 | case 0: |
| 1571 | args->auth_flavors[0] = RPC_AUTH_UNIX; | 1720 | args->auth_flavors[0] = RPC_AUTH_UNIX; |
| @@ -1623,6 +1772,9 @@ static int nfs4_validate_mount_data(void *options, | |||
| 1623 | &args->nfs_server.address)) | 1772 | &args->nfs_server.address)) |
| 1624 | return -EINVAL; | 1773 | return -EINVAL; |
| 1625 | 1774 | ||
| 1775 | nfs4_default_port((struct sockaddr *) | ||
| 1776 | &args->nfs_server.address); | ||
| 1777 | |||
| 1626 | switch (args->auth_flavor_len) { | 1778 | switch (args->auth_flavor_len) { |
| 1627 | case 0: | 1779 | case 0: |
| 1628 | args->auth_flavors[0] = RPC_AUTH_UNIX; | 1780 | args->auth_flavors[0] = RPC_AUTH_UNIX; |
| @@ -1643,21 +1795,16 @@ static int nfs4_validate_mount_data(void *options, | |||
| 1643 | len = c - dev_name; | 1795 | len = c - dev_name; |
| 1644 | if (len > NFS4_MAXNAMLEN) | 1796 | if (len > NFS4_MAXNAMLEN) |
| 1645 | return -ENAMETOOLONG; | 1797 | return -ENAMETOOLONG; |
| 1646 | args->nfs_server.hostname = kzalloc(len, GFP_KERNEL); | 1798 | /* N.B. caller will free nfs_server.hostname in all cases */ |
| 1647 | if (args->nfs_server.hostname == NULL) | 1799 | args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL); |
| 1648 | return -ENOMEM; | ||
| 1649 | strncpy(args->nfs_server.hostname, dev_name, len - 1); | ||
| 1650 | 1800 | ||
| 1651 | c++; /* step over the ':' */ | 1801 | c++; /* step over the ':' */ |
| 1652 | len = strlen(c); | 1802 | len = strlen(c); |
| 1653 | if (len > NFS4_MAXPATHLEN) | 1803 | if (len > NFS4_MAXPATHLEN) |
| 1654 | return -ENAMETOOLONG; | 1804 | return -ENAMETOOLONG; |
| 1655 | args->nfs_server.export_path = kzalloc(len + 1, GFP_KERNEL); | 1805 | args->nfs_server.export_path = kstrndup(c, len, GFP_KERNEL); |
| 1656 | if (args->nfs_server.export_path == NULL) | ||
| 1657 | return -ENOMEM; | ||
| 1658 | strncpy(args->nfs_server.export_path, c, len); | ||
| 1659 | 1806 | ||
| 1660 | dprintk("MNTPATH: %s\n", args->nfs_server.export_path); | 1807 | dprintk("NFS: MNTPATH: '%s'\n", args->nfs_server.export_path); |
| 1661 | 1808 | ||
| 1662 | if (args->client_address == NULL) | 1809 | if (args->client_address == NULL) |
| 1663 | goto out_no_client_address; | 1810 | goto out_no_client_address; |
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 233ad38161f9..757415363422 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c | |||
| @@ -14,6 +14,8 @@ | |||
| 14 | #include <linux/sched.h> | 14 | #include <linux/sched.h> |
| 15 | #include <linux/wait.h> | 15 | #include <linux/wait.h> |
| 16 | 16 | ||
| 17 | #include "internal.h" | ||
| 18 | |||
| 17 | struct nfs_unlinkdata { | 19 | struct nfs_unlinkdata { |
| 18 | struct hlist_node list; | 20 | struct hlist_node list; |
| 19 | struct nfs_removeargs args; | 21 | struct nfs_removeargs args; |
| @@ -69,24 +71,6 @@ static void nfs_dec_sillycount(struct inode *dir) | |||
| 69 | } | 71 | } |
| 70 | 72 | ||
| 71 | /** | 73 | /** |
| 72 | * nfs_async_unlink_init - Initialize the RPC info | ||
| 73 | * task: rpc_task of the sillydelete | ||
| 74 | */ | ||
| 75 | static void nfs_async_unlink_init(struct rpc_task *task, void *calldata) | ||
| 76 | { | ||
| 77 | struct nfs_unlinkdata *data = calldata; | ||
| 78 | struct inode *dir = data->dir; | ||
| 79 | struct rpc_message msg = { | ||
| 80 | .rpc_argp = &data->args, | ||
| 81 | .rpc_resp = &data->res, | ||
| 82 | .rpc_cred = data->cred, | ||
| 83 | }; | ||
| 84 | |||
| 85 | NFS_PROTO(dir)->unlink_setup(&msg, dir); | ||
| 86 | rpc_call_setup(task, &msg, 0); | ||
| 87 | } | ||
| 88 | |||
| 89 | /** | ||
| 90 | * nfs_async_unlink_done - Sillydelete post-processing | 74 | * nfs_async_unlink_done - Sillydelete post-processing |
| 91 | * @task: rpc_task of the sillydelete | 75 | * @task: rpc_task of the sillydelete |
| 92 | * | 76 | * |
| @@ -113,32 +97,45 @@ static void nfs_async_unlink_release(void *calldata) | |||
| 113 | struct nfs_unlinkdata *data = calldata; | 97 | struct nfs_unlinkdata *data = calldata; |
| 114 | 98 | ||
| 115 | nfs_dec_sillycount(data->dir); | 99 | nfs_dec_sillycount(data->dir); |
| 100 | nfs_sb_deactive(NFS_SERVER(data->dir)); | ||
| 116 | nfs_free_unlinkdata(data); | 101 | nfs_free_unlinkdata(data); |
| 117 | } | 102 | } |
| 118 | 103 | ||
| 119 | static const struct rpc_call_ops nfs_unlink_ops = { | 104 | static const struct rpc_call_ops nfs_unlink_ops = { |
| 120 | .rpc_call_prepare = nfs_async_unlink_init, | ||
| 121 | .rpc_call_done = nfs_async_unlink_done, | 105 | .rpc_call_done = nfs_async_unlink_done, |
| 122 | .rpc_release = nfs_async_unlink_release, | 106 | .rpc_release = nfs_async_unlink_release, |
| 123 | }; | 107 | }; |
| 124 | 108 | ||
| 125 | static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct nfs_unlinkdata *data) | 109 | static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct nfs_unlinkdata *data) |
| 126 | { | 110 | { |
| 111 | struct rpc_message msg = { | ||
| 112 | .rpc_argp = &data->args, | ||
| 113 | .rpc_resp = &data->res, | ||
| 114 | .rpc_cred = data->cred, | ||
| 115 | }; | ||
| 116 | struct rpc_task_setup task_setup_data = { | ||
| 117 | .rpc_message = &msg, | ||
| 118 | .callback_ops = &nfs_unlink_ops, | ||
| 119 | .callback_data = data, | ||
| 120 | .flags = RPC_TASK_ASYNC, | ||
| 121 | }; | ||
| 127 | struct rpc_task *task; | 122 | struct rpc_task *task; |
| 128 | struct dentry *alias; | 123 | struct dentry *alias; |
| 129 | 124 | ||
| 130 | alias = d_lookup(parent, &data->args.name); | 125 | alias = d_lookup(parent, &data->args.name); |
| 131 | if (alias != NULL) { | 126 | if (alias != NULL) { |
| 132 | int ret = 0; | 127 | int ret = 0; |
| 128 | |||
| 133 | /* | 129 | /* |
| 134 | * Hey, we raced with lookup... See if we need to transfer | 130 | * Hey, we raced with lookup... See if we need to transfer |
| 135 | * the sillyrename information to the aliased dentry. | 131 | * the sillyrename information to the aliased dentry. |
| 136 | */ | 132 | */ |
| 137 | nfs_free_dname(data); | 133 | nfs_free_dname(data); |
| 138 | spin_lock(&alias->d_lock); | 134 | spin_lock(&alias->d_lock); |
| 139 | if (!(alias->d_flags & DCACHE_NFSFS_RENAMED)) { | 135 | if (alias->d_inode != NULL && |
| 136 | !(alias->d_flags & DCACHE_NFSFS_RENAMED)) { | ||
| 140 | alias->d_fsdata = data; | 137 | alias->d_fsdata = data; |
| 141 | alias->d_flags ^= DCACHE_NFSFS_RENAMED; | 138 | alias->d_flags |= DCACHE_NFSFS_RENAMED; |
| 142 | ret = 1; | 139 | ret = 1; |
| 143 | } | 140 | } |
| 144 | spin_unlock(&alias->d_lock); | 141 | spin_unlock(&alias->d_lock); |
| @@ -151,10 +148,14 @@ static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct n | |||
| 151 | nfs_dec_sillycount(dir); | 148 | nfs_dec_sillycount(dir); |
| 152 | return 0; | 149 | return 0; |
| 153 | } | 150 | } |
| 151 | nfs_sb_active(NFS_SERVER(dir)); | ||
| 154 | data->args.fh = NFS_FH(dir); | 152 | data->args.fh = NFS_FH(dir); |
| 155 | nfs_fattr_init(&data->res.dir_attr); | 153 | nfs_fattr_init(&data->res.dir_attr); |
| 156 | 154 | ||
| 157 | task = rpc_run_task(NFS_CLIENT(dir), RPC_TASK_ASYNC, &nfs_unlink_ops, data); | 155 | NFS_PROTO(dir)->unlink_setup(&msg, dir); |
| 156 | |||
| 157 | task_setup_data.rpc_client = NFS_CLIENT(dir); | ||
| 158 | task = rpc_run_task(&task_setup_data); | ||
| 158 | if (!IS_ERR(task)) | 159 | if (!IS_ERR(task)) |
| 159 | rpc_put_task(task); | 160 | rpc_put_task(task); |
| 160 | return 1; | 161 | return 1; |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 51cc1bd6a116..5ac5b27b639a 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
| @@ -196,7 +196,7 @@ static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page, | |||
| 196 | } | 196 | } |
| 197 | /* Update file length */ | 197 | /* Update file length */ |
| 198 | nfs_grow_file(page, offset, count); | 198 | nfs_grow_file(page, offset, count); |
| 199 | nfs_unlock_request(req); | 199 | nfs_clear_page_tag_locked(req); |
| 200 | return 0; | 200 | return 0; |
| 201 | } | 201 | } |
| 202 | 202 | ||
| @@ -252,7 +252,6 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | |||
| 252 | struct page *page) | 252 | struct page *page) |
| 253 | { | 253 | { |
| 254 | struct inode *inode = page->mapping->host; | 254 | struct inode *inode = page->mapping->host; |
| 255 | struct nfs_inode *nfsi = NFS_I(inode); | ||
| 256 | struct nfs_page *req; | 255 | struct nfs_page *req; |
| 257 | int ret; | 256 | int ret; |
| 258 | 257 | ||
| @@ -263,10 +262,10 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | |||
| 263 | spin_unlock(&inode->i_lock); | 262 | spin_unlock(&inode->i_lock); |
| 264 | return 0; | 263 | return 0; |
| 265 | } | 264 | } |
| 266 | if (nfs_lock_request_dontget(req)) | 265 | if (nfs_set_page_tag_locked(req)) |
| 267 | break; | 266 | break; |
| 268 | /* Note: If we hold the page lock, as is the case in nfs_writepage, | 267 | /* Note: If we hold the page lock, as is the case in nfs_writepage, |
| 269 | * then the call to nfs_lock_request_dontget() will always | 268 | * then the call to nfs_set_page_tag_locked() will always |
| 270 | * succeed provided that someone hasn't already marked the | 269 | * succeed provided that someone hasn't already marked the |
| 271 | * request as dirty (in which case we don't care). | 270 | * request as dirty (in which case we don't care). |
| 272 | */ | 271 | */ |
| @@ -280,7 +279,7 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | |||
| 280 | if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) { | 279 | if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) { |
| 281 | /* This request is marked for commit */ | 280 | /* This request is marked for commit */ |
| 282 | spin_unlock(&inode->i_lock); | 281 | spin_unlock(&inode->i_lock); |
| 283 | nfs_unlock_request(req); | 282 | nfs_clear_page_tag_locked(req); |
| 284 | nfs_pageio_complete(pgio); | 283 | nfs_pageio_complete(pgio); |
| 285 | return 0; | 284 | return 0; |
| 286 | } | 285 | } |
| @@ -288,8 +287,6 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | |||
| 288 | spin_unlock(&inode->i_lock); | 287 | spin_unlock(&inode->i_lock); |
| 289 | BUG(); | 288 | BUG(); |
| 290 | } | 289 | } |
| 291 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, | ||
| 292 | NFS_PAGE_TAG_LOCKED); | ||
| 293 | spin_unlock(&inode->i_lock); | 290 | spin_unlock(&inode->i_lock); |
| 294 | nfs_pageio_add_request(pgio, req); | 291 | nfs_pageio_add_request(pgio, req); |
| 295 | return 0; | 292 | return 0; |
| @@ -381,6 +378,7 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) | |||
| 381 | set_page_private(req->wb_page, (unsigned long)req); | 378 | set_page_private(req->wb_page, (unsigned long)req); |
| 382 | nfsi->npages++; | 379 | nfsi->npages++; |
| 383 | kref_get(&req->wb_kref); | 380 | kref_get(&req->wb_kref); |
| 381 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); | ||
| 384 | return 0; | 382 | return 0; |
| 385 | } | 383 | } |
| 386 | 384 | ||
| @@ -596,7 +594,7 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, | |||
| 596 | spin_lock(&inode->i_lock); | 594 | spin_lock(&inode->i_lock); |
| 597 | req = nfs_page_find_request_locked(page); | 595 | req = nfs_page_find_request_locked(page); |
| 598 | if (req) { | 596 | if (req) { |
| 599 | if (!nfs_lock_request_dontget(req)) { | 597 | if (!nfs_set_page_tag_locked(req)) { |
| 600 | int error; | 598 | int error; |
| 601 | 599 | ||
| 602 | spin_unlock(&inode->i_lock); | 600 | spin_unlock(&inode->i_lock); |
| @@ -646,7 +644,7 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, | |||
| 646 | || req->wb_page != page | 644 | || req->wb_page != page |
| 647 | || !nfs_dirty_request(req) | 645 | || !nfs_dirty_request(req) |
| 648 | || offset > rqend || end < req->wb_offset) { | 646 | || offset > rqend || end < req->wb_offset) { |
| 649 | nfs_unlock_request(req); | 647 | nfs_clear_page_tag_locked(req); |
| 650 | return ERR_PTR(-EBUSY); | 648 | return ERR_PTR(-EBUSY); |
| 651 | } | 649 | } |
| 652 | 650 | ||
| @@ -755,7 +753,7 @@ static void nfs_writepage_release(struct nfs_page *req) | |||
| 755 | nfs_clear_page_tag_locked(req); | 753 | nfs_clear_page_tag_locked(req); |
| 756 | } | 754 | } |
| 757 | 755 | ||
| 758 | static inline int flush_task_priority(int how) | 756 | static int flush_task_priority(int how) |
| 759 | { | 757 | { |
| 760 | switch (how & (FLUSH_HIGHPRI|FLUSH_LOWPRI)) { | 758 | switch (how & (FLUSH_HIGHPRI|FLUSH_LOWPRI)) { |
| 761 | case FLUSH_HIGHPRI: | 759 | case FLUSH_HIGHPRI: |
| @@ -775,15 +773,31 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
| 775 | unsigned int count, unsigned int offset, | 773 | unsigned int count, unsigned int offset, |
| 776 | int how) | 774 | int how) |
| 777 | { | 775 | { |
| 778 | struct inode *inode; | 776 | struct inode *inode = req->wb_context->path.dentry->d_inode; |
| 779 | int flags; | 777 | int flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; |
| 778 | int priority = flush_task_priority(how); | ||
| 779 | struct rpc_task *task; | ||
| 780 | struct rpc_message msg = { | ||
| 781 | .rpc_argp = &data->args, | ||
| 782 | .rpc_resp = &data->res, | ||
| 783 | .rpc_cred = req->wb_context->cred, | ||
| 784 | }; | ||
| 785 | struct rpc_task_setup task_setup_data = { | ||
| 786 | .rpc_client = NFS_CLIENT(inode), | ||
| 787 | .task = &data->task, | ||
| 788 | .rpc_message = &msg, | ||
| 789 | .callback_ops = call_ops, | ||
| 790 | .callback_data = data, | ||
| 791 | .flags = flags, | ||
| 792 | .priority = priority, | ||
| 793 | }; | ||
| 780 | 794 | ||
| 781 | /* Set up the RPC argument and reply structs | 795 | /* Set up the RPC argument and reply structs |
| 782 | * NB: take care not to mess about with data->commit et al. */ | 796 | * NB: take care not to mess about with data->commit et al. */ |
| 783 | 797 | ||
| 784 | data->req = req; | 798 | data->req = req; |
| 785 | data->inode = inode = req->wb_context->path.dentry->d_inode; | 799 | data->inode = inode = req->wb_context->path.dentry->d_inode; |
| 786 | data->cred = req->wb_context->cred; | 800 | data->cred = msg.rpc_cred; |
| 787 | 801 | ||
| 788 | data->args.fh = NFS_FH(inode); | 802 | data->args.fh = NFS_FH(inode); |
| 789 | data->args.offset = req_offset(req) + offset; | 803 | data->args.offset = req_offset(req) + offset; |
| @@ -791,6 +805,12 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
| 791 | data->args.pages = data->pagevec; | 805 | data->args.pages = data->pagevec; |
| 792 | data->args.count = count; | 806 | data->args.count = count; |
| 793 | data->args.context = req->wb_context; | 807 | data->args.context = req->wb_context; |
| 808 | data->args.stable = NFS_UNSTABLE; | ||
| 809 | if (how & FLUSH_STABLE) { | ||
| 810 | data->args.stable = NFS_DATA_SYNC; | ||
| 811 | if (!NFS_I(inode)->ncommit) | ||
| 812 | data->args.stable = NFS_FILE_SYNC; | ||
| 813 | } | ||
| 794 | 814 | ||
| 795 | data->res.fattr = &data->fattr; | 815 | data->res.fattr = &data->fattr; |
| 796 | data->res.count = count; | 816 | data->res.count = count; |
| @@ -798,12 +818,7 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
| 798 | nfs_fattr_init(&data->fattr); | 818 | nfs_fattr_init(&data->fattr); |
| 799 | 819 | ||
| 800 | /* Set up the initial task struct. */ | 820 | /* Set up the initial task struct. */ |
| 801 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | 821 | NFS_PROTO(inode)->write_setup(data, &msg); |
| 802 | rpc_init_task(&data->task, NFS_CLIENT(inode), flags, call_ops, data); | ||
| 803 | NFS_PROTO(inode)->write_setup(data, how); | ||
| 804 | |||
| 805 | data->task.tk_priority = flush_task_priority(how); | ||
| 806 | data->task.tk_cookie = (unsigned long)inode; | ||
| 807 | 822 | ||
| 808 | dprintk("NFS: %5u initiated write call " | 823 | dprintk("NFS: %5u initiated write call " |
| 809 | "(req %s/%Ld, %u bytes @ offset %Lu)\n", | 824 | "(req %s/%Ld, %u bytes @ offset %Lu)\n", |
| @@ -812,16 +827,10 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
| 812 | (long long)NFS_FILEID(inode), | 827 | (long long)NFS_FILEID(inode), |
| 813 | count, | 828 | count, |
| 814 | (unsigned long long)data->args.offset); | 829 | (unsigned long long)data->args.offset); |
| 815 | } | ||
| 816 | |||
| 817 | static void nfs_execute_write(struct nfs_write_data *data) | ||
| 818 | { | ||
| 819 | struct rpc_clnt *clnt = NFS_CLIENT(data->inode); | ||
| 820 | sigset_t oldset; | ||
| 821 | 830 | ||
| 822 | rpc_clnt_sigmask(clnt, &oldset); | 831 | task = rpc_run_task(&task_setup_data); |
| 823 | rpc_execute(&data->task); | 832 | if (!IS_ERR(task)) |
| 824 | rpc_clnt_sigunmask(clnt, &oldset); | 833 | rpc_put_task(task); |
| 825 | } | 834 | } |
| 826 | 835 | ||
| 827 | /* | 836 | /* |
| @@ -868,7 +877,6 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned | |||
| 868 | wsize, offset, how); | 877 | wsize, offset, how); |
| 869 | offset += wsize; | 878 | offset += wsize; |
| 870 | nbytes -= wsize; | 879 | nbytes -= wsize; |
| 871 | nfs_execute_write(data); | ||
| 872 | } while (nbytes != 0); | 880 | } while (nbytes != 0); |
| 873 | 881 | ||
| 874 | return 0; | 882 | return 0; |
| @@ -916,7 +924,6 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned i | |||
| 916 | /* Set up the argument struct */ | 924 | /* Set up the argument struct */ |
| 917 | nfs_write_rpcsetup(req, data, &nfs_write_full_ops, count, 0, how); | 925 | nfs_write_rpcsetup(req, data, &nfs_write_full_ops, count, 0, how); |
| 918 | 926 | ||
| 919 | nfs_execute_write(data); | ||
| 920 | return 0; | 927 | return 0; |
| 921 | out_bad: | 928 | out_bad: |
| 922 | while (!list_empty(head)) { | 929 | while (!list_empty(head)) { |
| @@ -932,7 +939,7 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned i | |||
| 932 | static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, | 939 | static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, |
| 933 | struct inode *inode, int ioflags) | 940 | struct inode *inode, int ioflags) |
| 934 | { | 941 | { |
| 935 | int wsize = NFS_SERVER(inode)->wsize; | 942 | size_t wsize = NFS_SERVER(inode)->wsize; |
| 936 | 943 | ||
| 937 | if (wsize < PAGE_CACHE_SIZE) | 944 | if (wsize < PAGE_CACHE_SIZE) |
| 938 | nfs_pageio_init(pgio, inode, nfs_flush_multi, wsize, ioflags); | 945 | nfs_pageio_init(pgio, inode, nfs_flush_multi, wsize, ioflags); |
| @@ -1146,19 +1153,33 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
| 1146 | struct nfs_write_data *data, | 1153 | struct nfs_write_data *data, |
| 1147 | int how) | 1154 | int how) |
| 1148 | { | 1155 | { |
| 1149 | struct nfs_page *first; | 1156 | struct nfs_page *first = nfs_list_entry(head->next); |
| 1150 | struct inode *inode; | 1157 | struct inode *inode = first->wb_context->path.dentry->d_inode; |
| 1151 | int flags; | 1158 | int flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; |
| 1159 | int priority = flush_task_priority(how); | ||
| 1160 | struct rpc_task *task; | ||
| 1161 | struct rpc_message msg = { | ||
| 1162 | .rpc_argp = &data->args, | ||
| 1163 | .rpc_resp = &data->res, | ||
| 1164 | .rpc_cred = first->wb_context->cred, | ||
| 1165 | }; | ||
| 1166 | struct rpc_task_setup task_setup_data = { | ||
| 1167 | .task = &data->task, | ||
| 1168 | .rpc_client = NFS_CLIENT(inode), | ||
| 1169 | .rpc_message = &msg, | ||
| 1170 | .callback_ops = &nfs_commit_ops, | ||
| 1171 | .callback_data = data, | ||
| 1172 | .flags = flags, | ||
| 1173 | .priority = priority, | ||
| 1174 | }; | ||
| 1152 | 1175 | ||
| 1153 | /* Set up the RPC argument and reply structs | 1176 | /* Set up the RPC argument and reply structs |
| 1154 | * NB: take care not to mess about with data->commit et al. */ | 1177 | * NB: take care not to mess about with data->commit et al. */ |
| 1155 | 1178 | ||
| 1156 | list_splice_init(head, &data->pages); | 1179 | list_splice_init(head, &data->pages); |
| 1157 | first = nfs_list_entry(data->pages.next); | ||
| 1158 | inode = first->wb_context->path.dentry->d_inode; | ||
| 1159 | 1180 | ||
| 1160 | data->inode = inode; | 1181 | data->inode = inode; |
| 1161 | data->cred = first->wb_context->cred; | 1182 | data->cred = msg.rpc_cred; |
| 1162 | 1183 | ||
| 1163 | data->args.fh = NFS_FH(data->inode); | 1184 | data->args.fh = NFS_FH(data->inode); |
| 1164 | /* Note: we always request a commit of the entire inode */ | 1185 | /* Note: we always request a commit of the entire inode */ |
| @@ -1170,14 +1191,13 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
| 1170 | nfs_fattr_init(&data->fattr); | 1191 | nfs_fattr_init(&data->fattr); |
| 1171 | 1192 | ||
| 1172 | /* Set up the initial task struct. */ | 1193 | /* Set up the initial task struct. */ |
| 1173 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | 1194 | NFS_PROTO(inode)->commit_setup(data, &msg); |
| 1174 | rpc_init_task(&data->task, NFS_CLIENT(inode), flags, &nfs_commit_ops, data); | ||
| 1175 | NFS_PROTO(inode)->commit_setup(data, how); | ||
| 1176 | 1195 | ||
| 1177 | data->task.tk_priority = flush_task_priority(how); | ||
| 1178 | data->task.tk_cookie = (unsigned long)inode; | ||
| 1179 | |||
| 1180 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); | 1196 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); |
| 1197 | |||
| 1198 | task = rpc_run_task(&task_setup_data); | ||
| 1199 | if (!IS_ERR(task)) | ||
| 1200 | rpc_put_task(task); | ||
| 1181 | } | 1201 | } |
| 1182 | 1202 | ||
| 1183 | /* | 1203 | /* |
| @@ -1197,7 +1217,6 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how) | |||
| 1197 | /* Set up the argument struct */ | 1217 | /* Set up the argument struct */ |
| 1198 | nfs_commit_rpcsetup(head, data, how); | 1218 | nfs_commit_rpcsetup(head, data, how); |
| 1199 | 1219 | ||
| 1200 | nfs_execute_write(data); | ||
| 1201 | return 0; | 1220 | return 0; |
| 1202 | out_bad: | 1221 | out_bad: |
| 1203 | while (!list_empty(head)) { | 1222 | while (!list_empty(head)) { |
diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h index 6f1637c61e10..3d25bcd139d1 100644 --- a/include/linux/lockd/bind.h +++ b/include/linux/lockd/bind.h | |||
| @@ -33,9 +33,26 @@ struct nlmsvc_binding { | |||
| 33 | extern struct nlmsvc_binding * nlmsvc_ops; | 33 | extern struct nlmsvc_binding * nlmsvc_ops; |
| 34 | 34 | ||
| 35 | /* | 35 | /* |
| 36 | * Similar to nfs_client_initdata, but without the NFS-specific | ||
| 37 | * rpc_ops field. | ||
| 38 | */ | ||
| 39 | struct nlmclnt_initdata { | ||
| 40 | const char *hostname; | ||
| 41 | const struct sockaddr *address; | ||
| 42 | size_t addrlen; | ||
| 43 | unsigned short protocol; | ||
| 44 | u32 nfs_version; | ||
| 45 | }; | ||
| 46 | |||
| 47 | /* | ||
| 36 | * Functions exported by the lockd module | 48 | * Functions exported by the lockd module |
| 37 | */ | 49 | */ |
| 38 | extern int nlmclnt_proc(struct inode *, int, struct file_lock *); | 50 | |
| 51 | extern struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init); | ||
| 52 | extern void nlmclnt_done(struct nlm_host *host); | ||
| 53 | |||
| 54 | extern int nlmclnt_proc(struct nlm_host *host, int cmd, | ||
| 55 | struct file_lock *fl); | ||
| 39 | extern int lockd_up(int proto); | 56 | extern int lockd_up(int proto); |
| 40 | extern void lockd_down(void); | 57 | extern void lockd_down(void); |
| 41 | 58 | ||
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 2d15d4aac094..099ddb4481c0 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
| @@ -196,28 +196,67 @@ struct nfs_inode { | |||
| 196 | #define NFS_INO_STALE (2) /* possible stale inode */ | 196 | #define NFS_INO_STALE (2) /* possible stale inode */ |
| 197 | #define NFS_INO_ACL_LRU_SET (3) /* Inode is on the LRU list */ | 197 | #define NFS_INO_ACL_LRU_SET (3) /* Inode is on the LRU list */ |
| 198 | 198 | ||
| 199 | static inline struct nfs_inode *NFS_I(struct inode *inode) | 199 | static inline struct nfs_inode *NFS_I(const struct inode *inode) |
| 200 | { | 200 | { |
| 201 | return container_of(inode, struct nfs_inode, vfs_inode); | 201 | return container_of(inode, struct nfs_inode, vfs_inode); |
| 202 | } | 202 | } |
| 203 | #define NFS_SB(s) ((struct nfs_server *)(s->s_fs_info)) | ||
| 204 | 203 | ||
| 205 | #define NFS_FH(inode) (&NFS_I(inode)->fh) | 204 | static inline struct nfs_server *NFS_SB(const struct super_block *s) |
| 206 | #define NFS_SERVER(inode) (NFS_SB(inode->i_sb)) | 205 | { |
| 207 | #define NFS_CLIENT(inode) (NFS_SERVER(inode)->client) | 206 | return (struct nfs_server *)(s->s_fs_info); |
| 208 | #define NFS_PROTO(inode) (NFS_SERVER(inode)->nfs_client->rpc_ops) | 207 | } |
| 209 | #define NFS_COOKIEVERF(inode) (NFS_I(inode)->cookieverf) | 208 | |
| 210 | #define NFS_MINATTRTIMEO(inode) \ | 209 | static inline struct nfs_fh *NFS_FH(const struct inode *inode) |
| 211 | (S_ISDIR(inode->i_mode)? NFS_SERVER(inode)->acdirmin \ | 210 | { |
| 212 | : NFS_SERVER(inode)->acregmin) | 211 | return &NFS_I(inode)->fh; |
| 213 | #define NFS_MAXATTRTIMEO(inode) \ | 212 | } |
| 214 | (S_ISDIR(inode->i_mode)? NFS_SERVER(inode)->acdirmax \ | 213 | |
| 215 | : NFS_SERVER(inode)->acregmax) | 214 | static inline struct nfs_server *NFS_SERVER(const struct inode *inode) |
| 215 | { | ||
| 216 | return NFS_SB(inode->i_sb); | ||
| 217 | } | ||
| 218 | |||
| 219 | static inline struct rpc_clnt *NFS_CLIENT(const struct inode *inode) | ||
| 220 | { | ||
| 221 | return NFS_SERVER(inode)->client; | ||
| 222 | } | ||
| 223 | |||
| 224 | static inline const struct nfs_rpc_ops *NFS_PROTO(const struct inode *inode) | ||
| 225 | { | ||
| 226 | return NFS_SERVER(inode)->nfs_client->rpc_ops; | ||
| 227 | } | ||
| 228 | |||
| 229 | static inline __be32 *NFS_COOKIEVERF(const struct inode *inode) | ||
| 230 | { | ||
| 231 | return NFS_I(inode)->cookieverf; | ||
| 232 | } | ||
| 233 | |||
| 234 | static inline unsigned NFS_MINATTRTIMEO(const struct inode *inode) | ||
| 235 | { | ||
| 236 | struct nfs_server *nfss = NFS_SERVER(inode); | ||
| 237 | return S_ISDIR(inode->i_mode) ? nfss->acdirmin : nfss->acregmin; | ||
| 238 | } | ||
| 216 | 239 | ||
| 217 | #define NFS_FLAGS(inode) (NFS_I(inode)->flags) | 240 | static inline unsigned NFS_MAXATTRTIMEO(const struct inode *inode) |
| 218 | #define NFS_STALE(inode) (test_bit(NFS_INO_STALE, &NFS_FLAGS(inode))) | 241 | { |
| 242 | struct nfs_server *nfss = NFS_SERVER(inode); | ||
| 243 | return S_ISDIR(inode->i_mode) ? nfss->acdirmax : nfss->acregmax; | ||
| 244 | } | ||
| 219 | 245 | ||
| 220 | #define NFS_FILEID(inode) (NFS_I(inode)->fileid) | 246 | static inline int NFS_STALE(const struct inode *inode) |
| 247 | { | ||
| 248 | return test_bit(NFS_INO_STALE, &NFS_I(inode)->flags); | ||
| 249 | } | ||
| 250 | |||
| 251 | static inline __u64 NFS_FILEID(const struct inode *inode) | ||
| 252 | { | ||
| 253 | return NFS_I(inode)->fileid; | ||
| 254 | } | ||
| 255 | |||
| 256 | static inline void set_nfs_fileid(struct inode *inode, __u64 fileid) | ||
| 257 | { | ||
| 258 | NFS_I(inode)->fileid = fileid; | ||
| 259 | } | ||
| 221 | 260 | ||
| 222 | static inline void nfs_mark_for_revalidate(struct inode *inode) | 261 | static inline void nfs_mark_for_revalidate(struct inode *inode) |
| 223 | { | 262 | { |
| @@ -237,7 +276,7 @@ static inline int nfs_server_capable(struct inode *inode, int cap) | |||
| 237 | 276 | ||
| 238 | static inline int NFS_USE_READDIRPLUS(struct inode *inode) | 277 | static inline int NFS_USE_READDIRPLUS(struct inode *inode) |
| 239 | { | 278 | { |
| 240 | return test_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode)); | 279 | return test_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags); |
| 241 | } | 280 | } |
| 242 | 281 | ||
| 243 | static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf) | 282 | static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf) |
| @@ -366,6 +405,7 @@ extern const struct inode_operations nfs3_dir_inode_operations; | |||
| 366 | extern const struct file_operations nfs_dir_operations; | 405 | extern const struct file_operations nfs_dir_operations; |
| 367 | extern struct dentry_operations nfs_dentry_operations; | 406 | extern struct dentry_operations nfs_dentry_operations; |
| 368 | 407 | ||
| 408 | extern void nfs_force_lookup_revalidate(struct inode *dir); | ||
| 369 | extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh, struct nfs_fattr *fattr); | 409 | extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh, struct nfs_fattr *fattr); |
| 370 | extern int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags); | 410 | extern int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags); |
| 371 | extern void nfs_access_zap_cache(struct inode *inode); | 411 | extern void nfs_access_zap_cache(struct inode *inode); |
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 0cac49bc0955..3423c6761bf7 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h | |||
| @@ -3,8 +3,12 @@ | |||
| 3 | 3 | ||
| 4 | #include <linux/list.h> | 4 | #include <linux/list.h> |
| 5 | #include <linux/backing-dev.h> | 5 | #include <linux/backing-dev.h> |
| 6 | #include <linux/wait.h> | ||
| 7 | |||
| 8 | #include <asm/atomic.h> | ||
| 6 | 9 | ||
| 7 | struct nfs_iostats; | 10 | struct nfs_iostats; |
| 11 | struct nlm_host; | ||
| 8 | 12 | ||
| 9 | /* | 13 | /* |
| 10 | * The nfs_client identifies our client state to the server. | 14 | * The nfs_client identifies our client state to the server. |
| @@ -14,20 +18,19 @@ struct nfs_client { | |||
| 14 | int cl_cons_state; /* current construction state (-ve: init error) */ | 18 | int cl_cons_state; /* current construction state (-ve: init error) */ |
| 15 | #define NFS_CS_READY 0 /* ready to be used */ | 19 | #define NFS_CS_READY 0 /* ready to be used */ |
| 16 | #define NFS_CS_INITING 1 /* busy initialising */ | 20 | #define NFS_CS_INITING 1 /* busy initialising */ |
| 17 | int cl_nfsversion; /* NFS protocol version */ | ||
| 18 | unsigned long cl_res_state; /* NFS resources state */ | 21 | unsigned long cl_res_state; /* NFS resources state */ |
| 19 | #define NFS_CS_CALLBACK 1 /* - callback started */ | 22 | #define NFS_CS_CALLBACK 1 /* - callback started */ |
| 20 | #define NFS_CS_IDMAP 2 /* - idmap started */ | 23 | #define NFS_CS_IDMAP 2 /* - idmap started */ |
| 21 | #define NFS_CS_RENEWD 3 /* - renewd started */ | 24 | #define NFS_CS_RENEWD 3 /* - renewd started */ |
| 22 | struct sockaddr_in cl_addr; /* server identifier */ | 25 | struct sockaddr_storage cl_addr; /* server identifier */ |
| 26 | size_t cl_addrlen; | ||
| 23 | char * cl_hostname; /* hostname of server */ | 27 | char * cl_hostname; /* hostname of server */ |
| 24 | struct list_head cl_share_link; /* link in global client list */ | 28 | struct list_head cl_share_link; /* link in global client list */ |
| 25 | struct list_head cl_superblocks; /* List of nfs_server structs */ | 29 | struct list_head cl_superblocks; /* List of nfs_server structs */ |
| 26 | 30 | ||
| 27 | struct rpc_clnt * cl_rpcclient; | 31 | struct rpc_clnt * cl_rpcclient; |
| 28 | const struct nfs_rpc_ops *rpc_ops; /* NFS protocol vector */ | 32 | const struct nfs_rpc_ops *rpc_ops; /* NFS protocol vector */ |
| 29 | unsigned long retrans_timeo; /* retransmit timeout */ | 33 | int cl_proto; /* Network transport protocol */ |
| 30 | unsigned int retrans_count; /* number of retransmit tries */ | ||
| 31 | 34 | ||
| 32 | #ifdef CONFIG_NFS_V4 | 35 | #ifdef CONFIG_NFS_V4 |
| 33 | u64 cl_clientid; /* constant */ | 36 | u64 cl_clientid; /* constant */ |
| @@ -62,7 +65,7 @@ struct nfs_client { | |||
| 62 | /* Our own IP address, as a null-terminated string. | 65 | /* Our own IP address, as a null-terminated string. |
| 63 | * This is used to generate the clientid, and the callback address. | 66 | * This is used to generate the clientid, and the callback address. |
| 64 | */ | 67 | */ |
| 65 | char cl_ipaddr[16]; | 68 | char cl_ipaddr[48]; |
| 66 | unsigned char cl_id_uniquifier; | 69 | unsigned char cl_id_uniquifier; |
| 67 | #endif | 70 | #endif |
| 68 | }; | 71 | }; |
| @@ -78,6 +81,7 @@ struct nfs_server { | |||
| 78 | struct list_head master_link; /* link in master servers list */ | 81 | struct list_head master_link; /* link in master servers list */ |
| 79 | struct rpc_clnt * client; /* RPC client handle */ | 82 | struct rpc_clnt * client; /* RPC client handle */ |
| 80 | struct rpc_clnt * client_acl; /* ACL RPC client handle */ | 83 | struct rpc_clnt * client_acl; /* ACL RPC client handle */ |
| 84 | struct nlm_host *nlm_host; /* NLM client handle */ | ||
| 81 | struct nfs_iostats * io_stats; /* I/O statistics */ | 85 | struct nfs_iostats * io_stats; /* I/O statistics */ |
| 82 | struct backing_dev_info backing_dev_info; | 86 | struct backing_dev_info backing_dev_info; |
| 83 | atomic_long_t writeback; /* number of writeback pages */ | 87 | atomic_long_t writeback; /* number of writeback pages */ |
| @@ -110,6 +114,9 @@ struct nfs_server { | |||
| 110 | filesystem */ | 114 | filesystem */ |
| 111 | #endif | 115 | #endif |
| 112 | void (*destroy)(struct nfs_server *); | 116 | void (*destroy)(struct nfs_server *); |
| 117 | |||
| 118 | atomic_t active; /* Keep trace of any activity to this server */ | ||
| 119 | wait_queue_head_t active_wq; /* Wait for any activity to stop */ | ||
| 113 | }; | 120 | }; |
| 114 | 121 | ||
| 115 | /* Server capabilities */ | 122 | /* Server capabilities */ |
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index 30dbcc185e69..a1676e19e491 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h | |||
| @@ -83,6 +83,7 @@ extern void nfs_pageio_complete(struct nfs_pageio_descriptor *desc); | |||
| 83 | extern void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *, pgoff_t); | 83 | extern void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *, pgoff_t); |
| 84 | extern int nfs_wait_on_request(struct nfs_page *); | 84 | extern int nfs_wait_on_request(struct nfs_page *); |
| 85 | extern void nfs_unlock_request(struct nfs_page *req); | 85 | extern void nfs_unlock_request(struct nfs_page *req); |
| 86 | extern int nfs_set_page_tag_locked(struct nfs_page *req); | ||
| 86 | extern void nfs_clear_page_tag_locked(struct nfs_page *req); | 87 | extern void nfs_clear_page_tag_locked(struct nfs_page *req); |
| 87 | 88 | ||
| 88 | 89 | ||
| @@ -95,18 +96,6 @@ nfs_lock_request_dontget(struct nfs_page *req) | |||
| 95 | return !test_and_set_bit(PG_BUSY, &req->wb_flags); | 96 | return !test_and_set_bit(PG_BUSY, &req->wb_flags); |
| 96 | } | 97 | } |
| 97 | 98 | ||
| 98 | /* | ||
| 99 | * Lock the page of an asynchronous request and take a reference | ||
| 100 | */ | ||
| 101 | static inline int | ||
| 102 | nfs_lock_request(struct nfs_page *req) | ||
| 103 | { | ||
| 104 | if (test_and_set_bit(PG_BUSY, &req->wb_flags)) | ||
| 105 | return 0; | ||
| 106 | kref_get(&req->wb_kref); | ||
| 107 | return 1; | ||
| 108 | } | ||
| 109 | |||
| 110 | /** | 99 | /** |
| 111 | * nfs_list_add_request - Insert a request into a list | 100 | * nfs_list_add_request - Insert a request into a list |
| 112 | * @req: request | 101 | * @req: request |
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index daab252f2e5c..f301d0b8babc 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h | |||
| @@ -666,16 +666,17 @@ struct nfs4_rename_res { | |||
| 666 | struct nfs_fattr * new_fattr; | 666 | struct nfs_fattr * new_fattr; |
| 667 | }; | 667 | }; |
| 668 | 668 | ||
| 669 | #define NFS4_SETCLIENTID_NAMELEN (56) | ||
| 669 | struct nfs4_setclientid { | 670 | struct nfs4_setclientid { |
| 670 | const nfs4_verifier * sc_verifier; /* request */ | 671 | const nfs4_verifier * sc_verifier; |
| 671 | unsigned int sc_name_len; | 672 | unsigned int sc_name_len; |
| 672 | char sc_name[48]; /* request */ | 673 | char sc_name[NFS4_SETCLIENTID_NAMELEN]; |
| 673 | u32 sc_prog; /* request */ | 674 | u32 sc_prog; |
| 674 | unsigned int sc_netid_len; | 675 | unsigned int sc_netid_len; |
| 675 | char sc_netid[4]; /* request */ | 676 | char sc_netid[RPCBIND_MAXNETIDLEN]; |
| 676 | unsigned int sc_uaddr_len; | 677 | unsigned int sc_uaddr_len; |
| 677 | char sc_uaddr[24]; /* request */ | 678 | char sc_uaddr[RPCBIND_MAXUADDRLEN]; |
| 678 | u32 sc_cb_ident; /* request */ | 679 | u32 sc_cb_ident; |
| 679 | }; | 680 | }; |
| 680 | 681 | ||
| 681 | struct nfs4_statfs_arg { | 682 | struct nfs4_statfs_arg { |
| @@ -773,7 +774,7 @@ struct nfs_access_entry; | |||
| 773 | * RPC procedure vector for NFSv2/NFSv3 demuxing | 774 | * RPC procedure vector for NFSv2/NFSv3 demuxing |
| 774 | */ | 775 | */ |
| 775 | struct nfs_rpc_ops { | 776 | struct nfs_rpc_ops { |
| 776 | int version; /* Protocol version */ | 777 | u32 version; /* Protocol version */ |
| 777 | struct dentry_operations *dentry_ops; | 778 | struct dentry_operations *dentry_ops; |
| 778 | const struct inode_operations *dir_inode_ops; | 779 | const struct inode_operations *dir_inode_ops; |
| 779 | const struct inode_operations *file_inode_ops; | 780 | const struct inode_operations *file_inode_ops; |
| @@ -816,11 +817,11 @@ struct nfs_rpc_ops { | |||
| 816 | struct nfs_pathconf *); | 817 | struct nfs_pathconf *); |
| 817 | int (*set_capabilities)(struct nfs_server *, struct nfs_fh *); | 818 | int (*set_capabilities)(struct nfs_server *, struct nfs_fh *); |
| 818 | __be32 *(*decode_dirent)(__be32 *, struct nfs_entry *, int plus); | 819 | __be32 *(*decode_dirent)(__be32 *, struct nfs_entry *, int plus); |
| 819 | void (*read_setup) (struct nfs_read_data *); | 820 | void (*read_setup) (struct nfs_read_data *, struct rpc_message *); |
| 820 | int (*read_done) (struct rpc_task *, struct nfs_read_data *); | 821 | int (*read_done) (struct rpc_task *, struct nfs_read_data *); |
| 821 | void (*write_setup) (struct nfs_write_data *, int how); | 822 | void (*write_setup) (struct nfs_write_data *, struct rpc_message *); |
| 822 | int (*write_done) (struct rpc_task *, struct nfs_write_data *); | 823 | int (*write_done) (struct rpc_task *, struct nfs_write_data *); |
| 823 | void (*commit_setup) (struct nfs_write_data *, int how); | 824 | void (*commit_setup) (struct nfs_write_data *, struct rpc_message *); |
| 824 | int (*commit_done) (struct rpc_task *, struct nfs_write_data *); | 825 | int (*commit_done) (struct rpc_task *, struct nfs_write_data *); |
| 825 | int (*file_open) (struct inode *, struct file *); | 826 | int (*file_open) (struct inode *, struct file *); |
| 826 | int (*file_release) (struct inode *, struct file *); | 827 | int (*file_release) (struct inode *, struct file *); |
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index d9d5c5ad826c..3e9addc741c1 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h | |||
| @@ -46,6 +46,7 @@ struct rpc_clnt { | |||
| 46 | cl_autobind : 1;/* use getport() */ | 46 | cl_autobind : 1;/* use getport() */ |
| 47 | 47 | ||
| 48 | struct rpc_rtt * cl_rtt; /* RTO estimator data */ | 48 | struct rpc_rtt * cl_rtt; /* RTO estimator data */ |
| 49 | const struct rpc_timeout *cl_timeout; /* Timeout strategy */ | ||
| 49 | 50 | ||
| 50 | int cl_nodelen; /* nodename length */ | 51 | int cl_nodelen; /* nodename length */ |
| 51 | char cl_nodename[UNX_MAXNODENAME]; | 52 | char cl_nodename[UNX_MAXNODENAME]; |
| @@ -54,6 +55,7 @@ struct rpc_clnt { | |||
| 54 | struct dentry * cl_dentry; /* inode */ | 55 | struct dentry * cl_dentry; /* inode */ |
| 55 | struct rpc_clnt * cl_parent; /* Points to parent of clones */ | 56 | struct rpc_clnt * cl_parent; /* Points to parent of clones */ |
| 56 | struct rpc_rtt cl_rtt_default; | 57 | struct rpc_rtt cl_rtt_default; |
| 58 | struct rpc_timeout cl_timeout_default; | ||
| 57 | struct rpc_program * cl_program; | 59 | struct rpc_program * cl_program; |
| 58 | char cl_inline_name[32]; | 60 | char cl_inline_name[32]; |
| 59 | }; | 61 | }; |
| @@ -99,7 +101,7 @@ struct rpc_create_args { | |||
| 99 | struct sockaddr *address; | 101 | struct sockaddr *address; |
| 100 | size_t addrsize; | 102 | size_t addrsize; |
| 101 | struct sockaddr *saddress; | 103 | struct sockaddr *saddress; |
| 102 | struct rpc_timeout *timeout; | 104 | const struct rpc_timeout *timeout; |
| 103 | char *servername; | 105 | char *servername; |
| 104 | struct rpc_program *program; | 106 | struct rpc_program *program; |
| 105 | u32 version; | 107 | u32 version; |
| @@ -123,11 +125,10 @@ void rpc_shutdown_client(struct rpc_clnt *); | |||
| 123 | void rpc_release_client(struct rpc_clnt *); | 125 | void rpc_release_client(struct rpc_clnt *); |
| 124 | 126 | ||
| 125 | int rpcb_register(u32, u32, int, unsigned short, int *); | 127 | int rpcb_register(u32, u32, int, unsigned short, int *); |
| 126 | int rpcb_getport_sync(struct sockaddr_in *, __u32, __u32, int); | 128 | int rpcb_getport_sync(struct sockaddr_in *, u32, u32, int); |
| 127 | void rpcb_getport_async(struct rpc_task *); | 129 | void rpcb_getport_async(struct rpc_task *); |
| 128 | 130 | ||
| 129 | void rpc_call_setup(struct rpc_task *, struct rpc_message *, int); | 131 | void rpc_call_start(struct rpc_task *); |
| 130 | |||
| 131 | int rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, | 132 | int rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, |
| 132 | int flags, const struct rpc_call_ops *tk_ops, | 133 | int flags, const struct rpc_call_ops *tk_ops, |
| 133 | void *calldata); | 134 | void *calldata); |
| @@ -142,7 +143,7 @@ void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int); | |||
| 142 | size_t rpc_max_payload(struct rpc_clnt *); | 143 | size_t rpc_max_payload(struct rpc_clnt *); |
| 143 | void rpc_force_rebind(struct rpc_clnt *); | 144 | void rpc_force_rebind(struct rpc_clnt *); |
| 144 | size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t); | 145 | size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t); |
| 145 | char * rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t); | 146 | const char *rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t); |
| 146 | 147 | ||
| 147 | #endif /* __KERNEL__ */ | 148 | #endif /* __KERNEL__ */ |
| 148 | #endif /* _LINUX_SUNRPC_CLNT_H */ | 149 | #endif /* _LINUX_SUNRPC_CLNT_H */ |
diff --git a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h index c4beb5775111..70df4f1d8847 100644 --- a/include/linux/sunrpc/msg_prot.h +++ b/include/linux/sunrpc/msg_prot.h | |||
| @@ -152,5 +152,44 @@ typedef __be32 rpc_fraghdr; | |||
| 152 | */ | 152 | */ |
| 153 | #define RPCBIND_MAXNETIDLEN (4u) | 153 | #define RPCBIND_MAXNETIDLEN (4u) |
| 154 | 154 | ||
| 155 | /* | ||
| 156 | * Universal addresses are introduced in RFC 1833 and further spelled | ||
| 157 | * out in RFC 3530. RPCBIND_MAXUADDRLEN defines a maximum byte length | ||
| 158 | * of a universal address for use in allocating buffers and character | ||
| 159 | * arrays. | ||
| 160 | * | ||
| 161 | * Quoting RFC 3530, section 2.2: | ||
| 162 | * | ||
| 163 | * For TCP over IPv4 and for UDP over IPv4, the format of r_addr is the | ||
| 164 | * US-ASCII string: | ||
| 165 | * | ||
| 166 | * h1.h2.h3.h4.p1.p2 | ||
| 167 | * | ||
| 168 | * The prefix, "h1.h2.h3.h4", is the standard textual form for | ||
| 169 | * representing an IPv4 address, which is always four octets long. | ||
| 170 | * Assuming big-endian ordering, h1, h2, h3, and h4, are respectively, | ||
| 171 | * the first through fourth octets each converted to ASCII-decimal. | ||
| 172 | * Assuming big-endian ordering, p1 and p2 are, respectively, the first | ||
| 173 | * and second octets each converted to ASCII-decimal. For example, if a | ||
| 174 | * host, in big-endian order, has an address of 0x0A010307 and there is | ||
| 175 | * a service listening on, in big endian order, port 0x020F (decimal | ||
| 176 | * 527), then the complete universal address is "10.1.3.7.2.15". | ||
| 177 | * | ||
| 178 | * ... | ||
| 179 | * | ||
| 180 | * For TCP over IPv6 and for UDP over IPv6, the format of r_addr is the | ||
| 181 | * US-ASCII string: | ||
| 182 | * | ||
| 183 | * x1:x2:x3:x4:x5:x6:x7:x8.p1.p2 | ||
| 184 | * | ||
| 185 | * The suffix "p1.p2" is the service port, and is computed the same way | ||
| 186 | * as with universal addresses for TCP and UDP over IPv4. The prefix, | ||
| 187 | * "x1:x2:x3:x4:x5:x6:x7:x8", is the standard textual form for | ||
| 188 | * representing an IPv6 address as defined in Section 2.2 of [RFC2373]. | ||
| 189 | * Additionally, the two alternative forms specified in Section 2.2 of | ||
| 190 | * [RFC2373] are also acceptable. | ||
| 191 | */ | ||
| 192 | #define RPCBIND_MAXUADDRLEN (56u) | ||
| 193 | |||
| 155 | #endif /* __KERNEL__ */ | 194 | #endif /* __KERNEL__ */ |
| 156 | #endif /* _LINUX_SUNRPC_MSGPROT_H_ */ | 195 | #endif /* _LINUX_SUNRPC_MSGPROT_H_ */ |
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 8ea077db0099..ce3d1b132729 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h | |||
| @@ -56,8 +56,6 @@ struct rpc_task { | |||
| 56 | __u8 tk_garb_retry; | 56 | __u8 tk_garb_retry; |
| 57 | __u8 tk_cred_retry; | 57 | __u8 tk_cred_retry; |
| 58 | 58 | ||
| 59 | unsigned long tk_cookie; /* Cookie for batching tasks */ | ||
| 60 | |||
| 61 | /* | 59 | /* |
| 62 | * timeout_fn to be executed by timer bottom half | 60 | * timeout_fn to be executed by timer bottom half |
| 63 | * callback to be executed after waking up | 61 | * callback to be executed after waking up |
| @@ -78,7 +76,6 @@ struct rpc_task { | |||
| 78 | struct timer_list tk_timer; /* kernel timer */ | 76 | struct timer_list tk_timer; /* kernel timer */ |
| 79 | unsigned long tk_timeout; /* timeout for rpc_sleep() */ | 77 | unsigned long tk_timeout; /* timeout for rpc_sleep() */ |
| 80 | unsigned short tk_flags; /* misc flags */ | 78 | unsigned short tk_flags; /* misc flags */ |
| 81 | unsigned char tk_priority : 2;/* Task priority */ | ||
| 82 | unsigned long tk_runstate; /* Task run status */ | 79 | unsigned long tk_runstate; /* Task run status */ |
| 83 | struct workqueue_struct *tk_workqueue; /* Normally rpciod, but could | 80 | struct workqueue_struct *tk_workqueue; /* Normally rpciod, but could |
| 84 | * be any workqueue | 81 | * be any workqueue |
| @@ -94,6 +91,9 @@ struct rpc_task { | |||
| 94 | unsigned long tk_start; /* RPC task init timestamp */ | 91 | unsigned long tk_start; /* RPC task init timestamp */ |
| 95 | long tk_rtt; /* round-trip time (jiffies) */ | 92 | long tk_rtt; /* round-trip time (jiffies) */ |
| 96 | 93 | ||
| 94 | pid_t tk_owner; /* Process id for batching tasks */ | ||
| 95 | unsigned char tk_priority : 2;/* Task priority */ | ||
| 96 | |||
| 97 | #ifdef RPC_DEBUG | 97 | #ifdef RPC_DEBUG |
| 98 | unsigned short tk_pid; /* debugging aid */ | 98 | unsigned short tk_pid; /* debugging aid */ |
| 99 | #endif | 99 | #endif |
| @@ -117,6 +117,15 @@ struct rpc_call_ops { | |||
| 117 | void (*rpc_release)(void *); | 117 | void (*rpc_release)(void *); |
| 118 | }; | 118 | }; |
| 119 | 119 | ||
| 120 | struct rpc_task_setup { | ||
| 121 | struct rpc_task *task; | ||
| 122 | struct rpc_clnt *rpc_client; | ||
| 123 | const struct rpc_message *rpc_message; | ||
| 124 | const struct rpc_call_ops *callback_ops; | ||
| 125 | void *callback_data; | ||
| 126 | unsigned short flags; | ||
| 127 | signed char priority; | ||
| 128 | }; | ||
| 120 | 129 | ||
| 121 | /* | 130 | /* |
| 122 | * RPC task flags | 131 | * RPC task flags |
| @@ -180,10 +189,10 @@ struct rpc_call_ops { | |||
| 180 | * Note: if you change these, you must also change | 189 | * Note: if you change these, you must also change |
| 181 | * the task initialization definitions below. | 190 | * the task initialization definitions below. |
| 182 | */ | 191 | */ |
| 183 | #define RPC_PRIORITY_LOW 0 | 192 | #define RPC_PRIORITY_LOW (-1) |
| 184 | #define RPC_PRIORITY_NORMAL 1 | 193 | #define RPC_PRIORITY_NORMAL (0) |
| 185 | #define RPC_PRIORITY_HIGH 2 | 194 | #define RPC_PRIORITY_HIGH (1) |
| 186 | #define RPC_NR_PRIORITY (RPC_PRIORITY_HIGH+1) | 195 | #define RPC_NR_PRIORITY (1 + RPC_PRIORITY_HIGH - RPC_PRIORITY_LOW) |
| 187 | 196 | ||
| 188 | /* | 197 | /* |
| 189 | * RPC synchronization objects | 198 | * RPC synchronization objects |
| @@ -191,7 +200,7 @@ struct rpc_call_ops { | |||
| 191 | struct rpc_wait_queue { | 200 | struct rpc_wait_queue { |
| 192 | spinlock_t lock; | 201 | spinlock_t lock; |
| 193 | struct list_head tasks[RPC_NR_PRIORITY]; /* task queue for each priority level */ | 202 | struct list_head tasks[RPC_NR_PRIORITY]; /* task queue for each priority level */ |
| 194 | unsigned long cookie; /* cookie of last task serviced */ | 203 | pid_t owner; /* process id of last task serviced */ |
| 195 | unsigned char maxpriority; /* maximum priority (0 if queue is not a priority queue) */ | 204 | unsigned char maxpriority; /* maximum priority (0 if queue is not a priority queue) */ |
| 196 | unsigned char priority; /* current priority */ | 205 | unsigned char priority; /* current priority */ |
| 197 | unsigned char count; /* # task groups remaining serviced so far */ | 206 | unsigned char count; /* # task groups remaining serviced so far */ |
| @@ -208,41 +217,13 @@ struct rpc_wait_queue { | |||
| 208 | * performance of NFS operations such as read/write. | 217 | * performance of NFS operations such as read/write. |
| 209 | */ | 218 | */ |
| 210 | #define RPC_BATCH_COUNT 16 | 219 | #define RPC_BATCH_COUNT 16 |
| 211 | |||
| 212 | #ifndef RPC_DEBUG | ||
| 213 | # define RPC_WAITQ_INIT(var,qname) { \ | ||
| 214 | .lock = __SPIN_LOCK_UNLOCKED(var.lock), \ | ||
| 215 | .tasks = { \ | ||
| 216 | [0] = LIST_HEAD_INIT(var.tasks[0]), \ | ||
| 217 | [1] = LIST_HEAD_INIT(var.tasks[1]), \ | ||
| 218 | [2] = LIST_HEAD_INIT(var.tasks[2]), \ | ||
| 219 | }, \ | ||
| 220 | } | ||
| 221 | #else | ||
| 222 | # define RPC_WAITQ_INIT(var,qname) { \ | ||
| 223 | .lock = __SPIN_LOCK_UNLOCKED(var.lock), \ | ||
| 224 | .tasks = { \ | ||
| 225 | [0] = LIST_HEAD_INIT(var.tasks[0]), \ | ||
| 226 | [1] = LIST_HEAD_INIT(var.tasks[1]), \ | ||
| 227 | [2] = LIST_HEAD_INIT(var.tasks[2]), \ | ||
| 228 | }, \ | ||
| 229 | .name = qname, \ | ||
| 230 | } | ||
| 231 | #endif | ||
| 232 | # define RPC_WAITQ(var,qname) struct rpc_wait_queue var = RPC_WAITQ_INIT(var,qname) | ||
| 233 | |||
| 234 | #define RPC_IS_PRIORITY(q) ((q)->maxpriority > 0) | 220 | #define RPC_IS_PRIORITY(q) ((q)->maxpriority > 0) |
| 235 | 221 | ||
| 236 | /* | 222 | /* |
| 237 | * Function prototypes | 223 | * Function prototypes |
| 238 | */ | 224 | */ |
| 239 | struct rpc_task *rpc_new_task(struct rpc_clnt *, int flags, | 225 | struct rpc_task *rpc_new_task(const struct rpc_task_setup *); |
| 240 | const struct rpc_call_ops *ops, void *data); | 226 | struct rpc_task *rpc_run_task(const struct rpc_task_setup *); |
| 241 | struct rpc_task *rpc_run_task(struct rpc_clnt *clnt, int flags, | ||
| 242 | const struct rpc_call_ops *ops, void *data); | ||
| 243 | void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, | ||
| 244 | int flags, const struct rpc_call_ops *ops, | ||
| 245 | void *data); | ||
| 246 | void rpc_put_task(struct rpc_task *); | 227 | void rpc_put_task(struct rpc_task *); |
| 247 | void rpc_exit_task(struct rpc_task *); | 228 | void rpc_exit_task(struct rpc_task *); |
| 248 | void rpc_release_calldata(const struct rpc_call_ops *, void *); | 229 | void rpc_release_calldata(const struct rpc_call_ops *, void *); |
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 30b17b3bc1a9..b3ff9a815e6f 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h | |||
| @@ -120,7 +120,7 @@ struct rpc_xprt { | |||
| 120 | struct kref kref; /* Reference count */ | 120 | struct kref kref; /* Reference count */ |
| 121 | struct rpc_xprt_ops * ops; /* transport methods */ | 121 | struct rpc_xprt_ops * ops; /* transport methods */ |
| 122 | 122 | ||
| 123 | struct rpc_timeout timeout; /* timeout parms */ | 123 | const struct rpc_timeout *timeout; /* timeout parms */ |
| 124 | struct sockaddr_storage addr; /* server address */ | 124 | struct sockaddr_storage addr; /* server address */ |
| 125 | size_t addrlen; /* size of server address */ | 125 | size_t addrlen; /* size of server address */ |
| 126 | int prot; /* IP protocol */ | 126 | int prot; /* IP protocol */ |
| @@ -183,7 +183,7 @@ struct rpc_xprt { | |||
| 183 | bklog_u; /* backlog queue utilization */ | 183 | bklog_u; /* backlog queue utilization */ |
| 184 | } stat; | 184 | } stat; |
| 185 | 185 | ||
| 186 | char * address_strings[RPC_DISPLAY_MAX]; | 186 | const char *address_strings[RPC_DISPLAY_MAX]; |
| 187 | }; | 187 | }; |
| 188 | 188 | ||
| 189 | struct xprt_create { | 189 | struct xprt_create { |
| @@ -191,7 +191,6 @@ struct xprt_create { | |||
| 191 | struct sockaddr * srcaddr; /* optional local address */ | 191 | struct sockaddr * srcaddr; /* optional local address */ |
| 192 | struct sockaddr * dstaddr; /* remote peer address */ | 192 | struct sockaddr * dstaddr; /* remote peer address */ |
| 193 | size_t addrlen; | 193 | size_t addrlen; |
| 194 | struct rpc_timeout * timeout; /* optional timeout parameters */ | ||
| 195 | }; | 194 | }; |
| 196 | 195 | ||
| 197 | struct xprt_class { | 196 | struct xprt_class { |
| @@ -203,11 +202,6 @@ struct xprt_class { | |||
| 203 | }; | 202 | }; |
| 204 | 203 | ||
| 205 | /* | 204 | /* |
| 206 | * Transport operations used by ULPs | ||
| 207 | */ | ||
| 208 | void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long incr); | ||
| 209 | |||
| 210 | /* | ||
| 211 | * Generic internal transport functions | 205 | * Generic internal transport functions |
| 212 | */ | 206 | */ |
| 213 | struct rpc_xprt *xprt_create_transport(struct xprt_create *args); | 207 | struct rpc_xprt *xprt_create_transport(struct xprt_create *args); |
| @@ -245,7 +239,8 @@ void xprt_adjust_cwnd(struct rpc_task *task, int result); | |||
| 245 | struct rpc_rqst * xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid); | 239 | struct rpc_rqst * xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid); |
| 246 | void xprt_complete_rqst(struct rpc_task *task, int copied); | 240 | void xprt_complete_rqst(struct rpc_task *task, int copied); |
| 247 | void xprt_release_rqst_cong(struct rpc_task *task); | 241 | void xprt_release_rqst_cong(struct rpc_task *task); |
| 248 | void xprt_disconnect(struct rpc_xprt *xprt); | 242 | void xprt_disconnect_done(struct rpc_xprt *xprt); |
| 243 | void xprt_force_disconnect(struct rpc_xprt *xprt); | ||
| 249 | 244 | ||
| 250 | /* | 245 | /* |
| 251 | * Reserved bit positions in xprt->state | 246 | * Reserved bit positions in xprt->state |
| @@ -256,6 +251,7 @@ void xprt_disconnect(struct rpc_xprt *xprt); | |||
| 256 | #define XPRT_CLOSE_WAIT (3) | 251 | #define XPRT_CLOSE_WAIT (3) |
| 257 | #define XPRT_BOUND (4) | 252 | #define XPRT_BOUND (4) |
| 258 | #define XPRT_BINDING (5) | 253 | #define XPRT_BINDING (5) |
| 254 | #define XPRT_CLOSING (6) | ||
| 259 | 255 | ||
| 260 | static inline void xprt_set_connected(struct rpc_xprt *xprt) | 256 | static inline void xprt_set_connected(struct rpc_xprt *xprt) |
| 261 | { | 257 | { |
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 1ea27559b1de..bcd9abdb031c 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c | |||
| @@ -51,6 +51,7 @@ rpcauth_register(const struct rpc_authops *ops) | |||
| 51 | spin_unlock(&rpc_authflavor_lock); | 51 | spin_unlock(&rpc_authflavor_lock); |
| 52 | return ret; | 52 | return ret; |
| 53 | } | 53 | } |
| 54 | EXPORT_SYMBOL_GPL(rpcauth_register); | ||
| 54 | 55 | ||
| 55 | int | 56 | int |
| 56 | rpcauth_unregister(const struct rpc_authops *ops) | 57 | rpcauth_unregister(const struct rpc_authops *ops) |
| @@ -68,6 +69,7 @@ rpcauth_unregister(const struct rpc_authops *ops) | |||
| 68 | spin_unlock(&rpc_authflavor_lock); | 69 | spin_unlock(&rpc_authflavor_lock); |
| 69 | return ret; | 70 | return ret; |
| 70 | } | 71 | } |
| 72 | EXPORT_SYMBOL_GPL(rpcauth_unregister); | ||
| 71 | 73 | ||
| 72 | struct rpc_auth * | 74 | struct rpc_auth * |
| 73 | rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt) | 75 | rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt) |
| @@ -102,6 +104,7 @@ rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt) | |||
| 102 | out: | 104 | out: |
| 103 | return auth; | 105 | return auth; |
| 104 | } | 106 | } |
| 107 | EXPORT_SYMBOL_GPL(rpcauth_create); | ||
| 105 | 108 | ||
| 106 | void | 109 | void |
| 107 | rpcauth_release(struct rpc_auth *auth) | 110 | rpcauth_release(struct rpc_auth *auth) |
| @@ -151,6 +154,7 @@ rpcauth_init_credcache(struct rpc_auth *auth) | |||
| 151 | auth->au_credcache = new; | 154 | auth->au_credcache = new; |
| 152 | return 0; | 155 | return 0; |
| 153 | } | 156 | } |
| 157 | EXPORT_SYMBOL_GPL(rpcauth_init_credcache); | ||
| 154 | 158 | ||
| 155 | /* | 159 | /* |
| 156 | * Destroy a list of credentials | 160 | * Destroy a list of credentials |
| @@ -213,6 +217,7 @@ rpcauth_destroy_credcache(struct rpc_auth *auth) | |||
| 213 | kfree(cache); | 217 | kfree(cache); |
| 214 | } | 218 | } |
| 215 | } | 219 | } |
| 220 | EXPORT_SYMBOL_GPL(rpcauth_destroy_credcache); | ||
| 216 | 221 | ||
| 217 | /* | 222 | /* |
| 218 | * Remove stale credentials. Avoid sleeping inside the loop. | 223 | * Remove stale credentials. Avoid sleeping inside the loop. |
| @@ -332,6 +337,7 @@ found: | |||
| 332 | out: | 337 | out: |
| 333 | return cred; | 338 | return cred; |
| 334 | } | 339 | } |
| 340 | EXPORT_SYMBOL_GPL(rpcauth_lookup_credcache); | ||
| 335 | 341 | ||
| 336 | struct rpc_cred * | 342 | struct rpc_cred * |
| 337 | rpcauth_lookupcred(struct rpc_auth *auth, int flags) | 343 | rpcauth_lookupcred(struct rpc_auth *auth, int flags) |
| @@ -350,6 +356,7 @@ rpcauth_lookupcred(struct rpc_auth *auth, int flags) | |||
| 350 | put_group_info(acred.group_info); | 356 | put_group_info(acred.group_info); |
| 351 | return ret; | 357 | return ret; |
| 352 | } | 358 | } |
| 359 | EXPORT_SYMBOL_GPL(rpcauth_lookupcred); | ||
| 353 | 360 | ||
| 354 | void | 361 | void |
| 355 | rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred, | 362 | rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred, |
| @@ -366,7 +373,7 @@ rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred, | |||
| 366 | #endif | 373 | #endif |
| 367 | cred->cr_uid = acred->uid; | 374 | cred->cr_uid = acred->uid; |
| 368 | } | 375 | } |
| 369 | EXPORT_SYMBOL(rpcauth_init_cred); | 376 | EXPORT_SYMBOL_GPL(rpcauth_init_cred); |
| 370 | 377 | ||
| 371 | struct rpc_cred * | 378 | struct rpc_cred * |
| 372 | rpcauth_bindcred(struct rpc_task *task) | 379 | rpcauth_bindcred(struct rpc_task *task) |
| @@ -378,6 +385,7 @@ rpcauth_bindcred(struct rpc_task *task) | |||
| 378 | .group_info = current->group_info, | 385 | .group_info = current->group_info, |
| 379 | }; | 386 | }; |
| 380 | struct rpc_cred *ret; | 387 | struct rpc_cred *ret; |
| 388 | sigset_t oldset; | ||
| 381 | int flags = 0; | 389 | int flags = 0; |
| 382 | 390 | ||
| 383 | dprintk("RPC: %5u looking up %s cred\n", | 391 | dprintk("RPC: %5u looking up %s cred\n", |
| @@ -385,7 +393,9 @@ rpcauth_bindcred(struct rpc_task *task) | |||
| 385 | get_group_info(acred.group_info); | 393 | get_group_info(acred.group_info); |
| 386 | if (task->tk_flags & RPC_TASK_ROOTCREDS) | 394 | if (task->tk_flags & RPC_TASK_ROOTCREDS) |
| 387 | flags |= RPCAUTH_LOOKUP_ROOTCREDS; | 395 | flags |= RPCAUTH_LOOKUP_ROOTCREDS; |
| 396 | rpc_clnt_sigmask(task->tk_client, &oldset); | ||
| 388 | ret = auth->au_ops->lookup_cred(auth, &acred, flags); | 397 | ret = auth->au_ops->lookup_cred(auth, &acred, flags); |
| 398 | rpc_clnt_sigunmask(task->tk_client, &oldset); | ||
| 389 | if (!IS_ERR(ret)) | 399 | if (!IS_ERR(ret)) |
| 390 | task->tk_msg.rpc_cred = ret; | 400 | task->tk_msg.rpc_cred = ret; |
| 391 | else | 401 | else |
| @@ -435,6 +445,7 @@ need_lock: | |||
| 435 | out_destroy: | 445 | out_destroy: |
| 436 | cred->cr_ops->crdestroy(cred); | 446 | cred->cr_ops->crdestroy(cred); |
| 437 | } | 447 | } |
| 448 | EXPORT_SYMBOL_GPL(put_rpccred); | ||
| 438 | 449 | ||
| 439 | void | 450 | void |
| 440 | rpcauth_unbindcred(struct rpc_task *task) | 451 | rpcauth_unbindcred(struct rpc_task *task) |
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 1f2d85e869c0..6dac38792288 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
| @@ -472,16 +472,15 @@ gss_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg, | |||
| 472 | char __user *dst, size_t buflen) | 472 | char __user *dst, size_t buflen) |
| 473 | { | 473 | { |
| 474 | char *data = (char *)msg->data + msg->copied; | 474 | char *data = (char *)msg->data + msg->copied; |
| 475 | ssize_t mlen = msg->len; | 475 | size_t mlen = min(msg->len, buflen); |
| 476 | ssize_t left; | 476 | unsigned long left; |
| 477 | 477 | ||
| 478 | if (mlen > buflen) | ||
| 479 | mlen = buflen; | ||
| 480 | left = copy_to_user(dst, data, mlen); | 478 | left = copy_to_user(dst, data, mlen); |
| 481 | if (left < 0) { | 479 | if (left == mlen) { |
| 482 | msg->errno = left; | 480 | msg->errno = -EFAULT; |
| 483 | return left; | 481 | return -EFAULT; |
| 484 | } | 482 | } |
| 483 | |||
| 485 | mlen -= left; | 484 | mlen -= left; |
| 486 | msg->copied += mlen; | 485 | msg->copied += mlen; |
| 487 | msg->errno = 0; | 486 | msg->errno = 0; |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 76be83ee4b04..924916ceaa43 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include <linux/smp_lock.h> | 30 | #include <linux/smp_lock.h> |
| 31 | #include <linux/utsname.h> | 31 | #include <linux/utsname.h> |
| 32 | #include <linux/workqueue.h> | 32 | #include <linux/workqueue.h> |
| 33 | #include <linux/in6.h> | ||
| 33 | 34 | ||
| 34 | #include <linux/sunrpc/clnt.h> | 35 | #include <linux/sunrpc/clnt.h> |
| 35 | #include <linux/sunrpc/rpc_pipe_fs.h> | 36 | #include <linux/sunrpc/rpc_pipe_fs.h> |
| @@ -121,8 +122,9 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) | |||
| 121 | } | 122 | } |
| 122 | } | 123 | } |
| 123 | 124 | ||
| 124 | static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, struct rpc_program *program, u32 vers, rpc_authflavor_t flavor) | 125 | static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt) |
| 125 | { | 126 | { |
| 127 | struct rpc_program *program = args->program; | ||
| 126 | struct rpc_version *version; | 128 | struct rpc_version *version; |
| 127 | struct rpc_clnt *clnt = NULL; | 129 | struct rpc_clnt *clnt = NULL; |
| 128 | struct rpc_auth *auth; | 130 | struct rpc_auth *auth; |
| @@ -131,13 +133,13 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s | |||
| 131 | 133 | ||
| 132 | /* sanity check the name before trying to print it */ | 134 | /* sanity check the name before trying to print it */ |
| 133 | err = -EINVAL; | 135 | err = -EINVAL; |
| 134 | len = strlen(servname); | 136 | len = strlen(args->servername); |
| 135 | if (len > RPC_MAXNETNAMELEN) | 137 | if (len > RPC_MAXNETNAMELEN) |
| 136 | goto out_no_rpciod; | 138 | goto out_no_rpciod; |
| 137 | len++; | 139 | len++; |
| 138 | 140 | ||
| 139 | dprintk("RPC: creating %s client for %s (xprt %p)\n", | 141 | dprintk("RPC: creating %s client for %s (xprt %p)\n", |
| 140 | program->name, servname, xprt); | 142 | program->name, args->servername, xprt); |
| 141 | 143 | ||
| 142 | err = rpciod_up(); | 144 | err = rpciod_up(); |
| 143 | if (err) | 145 | if (err) |
| @@ -145,7 +147,11 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s | |||
| 145 | err = -EINVAL; | 147 | err = -EINVAL; |
| 146 | if (!xprt) | 148 | if (!xprt) |
| 147 | goto out_no_xprt; | 149 | goto out_no_xprt; |
| 148 | if (vers >= program->nrvers || !(version = program->version[vers])) | 150 | |
| 151 | if (args->version >= program->nrvers) | ||
| 152 | goto out_err; | ||
| 153 | version = program->version[args->version]; | ||
| 154 | if (version == NULL) | ||
| 149 | goto out_err; | 155 | goto out_err; |
| 150 | 156 | ||
| 151 | err = -ENOMEM; | 157 | err = -ENOMEM; |
| @@ -157,12 +163,12 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s | |||
| 157 | clnt->cl_server = clnt->cl_inline_name; | 163 | clnt->cl_server = clnt->cl_inline_name; |
| 158 | if (len > sizeof(clnt->cl_inline_name)) { | 164 | if (len > sizeof(clnt->cl_inline_name)) { |
| 159 | char *buf = kmalloc(len, GFP_KERNEL); | 165 | char *buf = kmalloc(len, GFP_KERNEL); |
| 160 | if (buf != 0) | 166 | if (buf != NULL) |
| 161 | clnt->cl_server = buf; | 167 | clnt->cl_server = buf; |
| 162 | else | 168 | else |
| 163 | len = sizeof(clnt->cl_inline_name); | 169 | len = sizeof(clnt->cl_inline_name); |
| 164 | } | 170 | } |
| 165 | strlcpy(clnt->cl_server, servname, len); | 171 | strlcpy(clnt->cl_server, args->servername, len); |
| 166 | 172 | ||
| 167 | clnt->cl_xprt = xprt; | 173 | clnt->cl_xprt = xprt; |
| 168 | clnt->cl_procinfo = version->procs; | 174 | clnt->cl_procinfo = version->procs; |
| @@ -182,8 +188,15 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s | |||
| 182 | if (!xprt_bound(clnt->cl_xprt)) | 188 | if (!xprt_bound(clnt->cl_xprt)) |
| 183 | clnt->cl_autobind = 1; | 189 | clnt->cl_autobind = 1; |
| 184 | 190 | ||
| 191 | clnt->cl_timeout = xprt->timeout; | ||
| 192 | if (args->timeout != NULL) { | ||
| 193 | memcpy(&clnt->cl_timeout_default, args->timeout, | ||
| 194 | sizeof(clnt->cl_timeout_default)); | ||
| 195 | clnt->cl_timeout = &clnt->cl_timeout_default; | ||
| 196 | } | ||
| 197 | |||
| 185 | clnt->cl_rtt = &clnt->cl_rtt_default; | 198 | clnt->cl_rtt = &clnt->cl_rtt_default; |
| 186 | rpc_init_rtt(&clnt->cl_rtt_default, xprt->timeout.to_initval); | 199 | rpc_init_rtt(&clnt->cl_rtt_default, clnt->cl_timeout->to_initval); |
| 187 | 200 | ||
| 188 | kref_init(&clnt->cl_kref); | 201 | kref_init(&clnt->cl_kref); |
| 189 | 202 | ||
| @@ -191,10 +204,10 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s | |||
| 191 | if (err < 0) | 204 | if (err < 0) |
| 192 | goto out_no_path; | 205 | goto out_no_path; |
| 193 | 206 | ||
| 194 | auth = rpcauth_create(flavor, clnt); | 207 | auth = rpcauth_create(args->authflavor, clnt); |
| 195 | if (IS_ERR(auth)) { | 208 | if (IS_ERR(auth)) { |
| 196 | printk(KERN_INFO "RPC: Couldn't create auth handle (flavor %u)\n", | 209 | printk(KERN_INFO "RPC: Couldn't create auth handle (flavor %u)\n", |
| 197 | flavor); | 210 | args->authflavor); |
| 198 | err = PTR_ERR(auth); | 211 | err = PTR_ERR(auth); |
| 199 | goto out_no_auth; | 212 | goto out_no_auth; |
| 200 | } | 213 | } |
| @@ -245,9 +258,8 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) | |||
| 245 | .srcaddr = args->saddress, | 258 | .srcaddr = args->saddress, |
| 246 | .dstaddr = args->address, | 259 | .dstaddr = args->address, |
| 247 | .addrlen = args->addrsize, | 260 | .addrlen = args->addrsize, |
| 248 | .timeout = args->timeout | ||
| 249 | }; | 261 | }; |
| 250 | char servername[20]; | 262 | char servername[48]; |
| 251 | 263 | ||
| 252 | xprt = xprt_create_transport(&xprtargs); | 264 | xprt = xprt_create_transport(&xprtargs); |
| 253 | if (IS_ERR(xprt)) | 265 | if (IS_ERR(xprt)) |
| @@ -258,13 +270,34 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) | |||
| 258 | * up a string representation of the passed-in address. | 270 | * up a string representation of the passed-in address. |
| 259 | */ | 271 | */ |
| 260 | if (args->servername == NULL) { | 272 | if (args->servername == NULL) { |
| 261 | struct sockaddr_in *addr = | 273 | servername[0] = '\0'; |
| 262 | (struct sockaddr_in *) args->address; | 274 | switch (args->address->sa_family) { |
| 263 | snprintf(servername, sizeof(servername), NIPQUAD_FMT, | 275 | case AF_INET: { |
| 264 | NIPQUAD(addr->sin_addr.s_addr)); | 276 | struct sockaddr_in *sin = |
| 277 | (struct sockaddr_in *)args->address; | ||
| 278 | snprintf(servername, sizeof(servername), NIPQUAD_FMT, | ||
| 279 | NIPQUAD(sin->sin_addr.s_addr)); | ||
| 280 | break; | ||
| 281 | } | ||
| 282 | case AF_INET6: { | ||
| 283 | struct sockaddr_in6 *sin = | ||
| 284 | (struct sockaddr_in6 *)args->address; | ||
| 285 | snprintf(servername, sizeof(servername), NIP6_FMT, | ||
| 286 | NIP6(sin->sin6_addr)); | ||
| 287 | break; | ||
| 288 | } | ||
| 289 | default: | ||
| 290 | /* caller wants default server name, but | ||
| 291 | * address family isn't recognized. */ | ||
| 292 | return ERR_PTR(-EINVAL); | ||
| 293 | } | ||
| 265 | args->servername = servername; | 294 | args->servername = servername; |
| 266 | } | 295 | } |
| 267 | 296 | ||
| 297 | xprt = xprt_create_transport(&xprtargs); | ||
| 298 | if (IS_ERR(xprt)) | ||
| 299 | return (struct rpc_clnt *)xprt; | ||
| 300 | |||
| 268 | /* | 301 | /* |
| 269 | * By default, kernel RPC client connects from a reserved port. | 302 | * By default, kernel RPC client connects from a reserved port. |
| 270 | * CAP_NET_BIND_SERVICE will not be set for unprivileged requesters, | 303 | * CAP_NET_BIND_SERVICE will not be set for unprivileged requesters, |
| @@ -275,8 +308,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) | |||
| 275 | if (args->flags & RPC_CLNT_CREATE_NONPRIVPORT) | 308 | if (args->flags & RPC_CLNT_CREATE_NONPRIVPORT) |
| 276 | xprt->resvport = 0; | 309 | xprt->resvport = 0; |
| 277 | 310 | ||
| 278 | clnt = rpc_new_client(xprt, args->servername, args->program, | 311 | clnt = rpc_new_client(args, xprt); |
| 279 | args->version, args->authflavor); | ||
| 280 | if (IS_ERR(clnt)) | 312 | if (IS_ERR(clnt)) |
| 281 | return clnt; | 313 | return clnt; |
| 282 | 314 | ||
| @@ -322,7 +354,7 @@ rpc_clone_client(struct rpc_clnt *clnt) | |||
| 322 | new->cl_autobind = 0; | 354 | new->cl_autobind = 0; |
| 323 | INIT_LIST_HEAD(&new->cl_tasks); | 355 | INIT_LIST_HEAD(&new->cl_tasks); |
| 324 | spin_lock_init(&new->cl_lock); | 356 | spin_lock_init(&new->cl_lock); |
| 325 | rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval); | 357 | rpc_init_rtt(&new->cl_rtt_default, clnt->cl_timeout->to_initval); |
| 326 | new->cl_metrics = rpc_alloc_iostats(clnt); | 358 | new->cl_metrics = rpc_alloc_iostats(clnt); |
| 327 | if (new->cl_metrics == NULL) | 359 | if (new->cl_metrics == NULL) |
| 328 | goto out_no_stats; | 360 | goto out_no_stats; |
| @@ -345,6 +377,7 @@ out_no_clnt: | |||
| 345 | dprintk("RPC: %s: returned error %d\n", __FUNCTION__, err); | 377 | dprintk("RPC: %s: returned error %d\n", __FUNCTION__, err); |
| 346 | return ERR_PTR(err); | 378 | return ERR_PTR(err); |
| 347 | } | 379 | } |
| 380 | EXPORT_SYMBOL_GPL(rpc_clone_client); | ||
| 348 | 381 | ||
| 349 | /* | 382 | /* |
| 350 | * Properly shut down an RPC client, terminating all outstanding | 383 | * Properly shut down an RPC client, terminating all outstanding |
| @@ -363,6 +396,7 @@ void rpc_shutdown_client(struct rpc_clnt *clnt) | |||
| 363 | 396 | ||
| 364 | rpc_release_client(clnt); | 397 | rpc_release_client(clnt); |
| 365 | } | 398 | } |
| 399 | EXPORT_SYMBOL_GPL(rpc_shutdown_client); | ||
| 366 | 400 | ||
| 367 | /* | 401 | /* |
| 368 | * Free an RPC client | 402 | * Free an RPC client |
| @@ -467,6 +501,7 @@ struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old, | |||
| 467 | out: | 501 | out: |
| 468 | return clnt; | 502 | return clnt; |
| 469 | } | 503 | } |
| 504 | EXPORT_SYMBOL_GPL(rpc_bind_new_program); | ||
| 470 | 505 | ||
| 471 | /* | 506 | /* |
| 472 | * Default callback for async RPC calls | 507 | * Default callback for async RPC calls |
| @@ -498,12 +533,12 @@ static void rpc_save_sigmask(sigset_t *oldset, int intr) | |||
| 498 | sigprocmask(SIG_BLOCK, &sigmask, oldset); | 533 | sigprocmask(SIG_BLOCK, &sigmask, oldset); |
| 499 | } | 534 | } |
| 500 | 535 | ||
| 501 | static inline void rpc_task_sigmask(struct rpc_task *task, sigset_t *oldset) | 536 | static void rpc_task_sigmask(struct rpc_task *task, sigset_t *oldset) |
| 502 | { | 537 | { |
| 503 | rpc_save_sigmask(oldset, !RPC_TASK_UNINTERRUPTIBLE(task)); | 538 | rpc_save_sigmask(oldset, !RPC_TASK_UNINTERRUPTIBLE(task)); |
| 504 | } | 539 | } |
| 505 | 540 | ||
| 506 | static inline void rpc_restore_sigmask(sigset_t *oldset) | 541 | static void rpc_restore_sigmask(sigset_t *oldset) |
| 507 | { | 542 | { |
| 508 | sigprocmask(SIG_SETMASK, oldset, NULL); | 543 | sigprocmask(SIG_SETMASK, oldset, NULL); |
| 509 | } | 544 | } |
| @@ -512,45 +547,49 @@ void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset) | |||
| 512 | { | 547 | { |
| 513 | rpc_save_sigmask(oldset, clnt->cl_intr); | 548 | rpc_save_sigmask(oldset, clnt->cl_intr); |
| 514 | } | 549 | } |
| 550 | EXPORT_SYMBOL_GPL(rpc_clnt_sigmask); | ||
| 515 | 551 | ||
| 516 | void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset) | 552 | void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset) |
| 517 | { | 553 | { |
| 518 | rpc_restore_sigmask(oldset); | 554 | rpc_restore_sigmask(oldset); |
| 519 | } | 555 | } |
| 556 | EXPORT_SYMBOL_GPL(rpc_clnt_sigunmask); | ||
| 520 | 557 | ||
| 521 | static | 558 | /** |
| 522 | struct rpc_task *rpc_do_run_task(struct rpc_clnt *clnt, | 559 | * rpc_run_task - Allocate a new RPC task, then run rpc_execute against it |
| 523 | struct rpc_message *msg, | 560 | * @task_setup_data: pointer to task initialisation data |
| 524 | int flags, | 561 | */ |
| 525 | const struct rpc_call_ops *ops, | 562 | struct rpc_task *rpc_run_task(const struct rpc_task_setup *task_setup_data) |
| 526 | void *data) | ||
| 527 | { | 563 | { |
| 528 | struct rpc_task *task, *ret; | 564 | struct rpc_task *task, *ret; |
| 529 | sigset_t oldset; | 565 | sigset_t oldset; |
| 530 | 566 | ||
| 531 | task = rpc_new_task(clnt, flags, ops, data); | 567 | task = rpc_new_task(task_setup_data); |
| 532 | if (task == NULL) { | 568 | if (task == NULL) { |
| 533 | rpc_release_calldata(ops, data); | 569 | rpc_release_calldata(task_setup_data->callback_ops, |
| 534 | return ERR_PTR(-ENOMEM); | 570 | task_setup_data->callback_data); |
| 571 | ret = ERR_PTR(-ENOMEM); | ||
| 572 | goto out; | ||
| 535 | } | 573 | } |
| 536 | 574 | ||
| 537 | /* Mask signals on synchronous RPC calls and RPCSEC_GSS upcalls */ | 575 | if (task->tk_status != 0) { |
| 538 | rpc_task_sigmask(task, &oldset); | 576 | ret = ERR_PTR(task->tk_status); |
| 539 | if (msg != NULL) { | 577 | rpc_put_task(task); |
| 540 | rpc_call_setup(task, msg, 0); | 578 | goto out; |
| 541 | if (task->tk_status != 0) { | ||
| 542 | ret = ERR_PTR(task->tk_status); | ||
| 543 | rpc_put_task(task); | ||
| 544 | goto out; | ||
| 545 | } | ||
| 546 | } | 579 | } |
| 547 | atomic_inc(&task->tk_count); | 580 | atomic_inc(&task->tk_count); |
| 548 | rpc_execute(task); | 581 | /* Mask signals on synchronous RPC calls and RPCSEC_GSS upcalls */ |
| 582 | if (!RPC_IS_ASYNC(task)) { | ||
| 583 | rpc_task_sigmask(task, &oldset); | ||
| 584 | rpc_execute(task); | ||
| 585 | rpc_restore_sigmask(&oldset); | ||
| 586 | } else | ||
| 587 | rpc_execute(task); | ||
| 549 | ret = task; | 588 | ret = task; |
| 550 | out: | 589 | out: |
| 551 | rpc_restore_sigmask(&oldset); | ||
| 552 | return ret; | 590 | return ret; |
| 553 | } | 591 | } |
| 592 | EXPORT_SYMBOL_GPL(rpc_run_task); | ||
| 554 | 593 | ||
| 555 | /** | 594 | /** |
| 556 | * rpc_call_sync - Perform a synchronous RPC call | 595 | * rpc_call_sync - Perform a synchronous RPC call |
| @@ -561,17 +600,24 @@ out: | |||
| 561 | int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) | 600 | int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) |
| 562 | { | 601 | { |
| 563 | struct rpc_task *task; | 602 | struct rpc_task *task; |
| 603 | struct rpc_task_setup task_setup_data = { | ||
| 604 | .rpc_client = clnt, | ||
| 605 | .rpc_message = msg, | ||
| 606 | .callback_ops = &rpc_default_ops, | ||
| 607 | .flags = flags, | ||
| 608 | }; | ||
| 564 | int status; | 609 | int status; |
| 565 | 610 | ||
| 566 | BUG_ON(flags & RPC_TASK_ASYNC); | 611 | BUG_ON(flags & RPC_TASK_ASYNC); |
| 567 | 612 | ||
| 568 | task = rpc_do_run_task(clnt, msg, flags, &rpc_default_ops, NULL); | 613 | task = rpc_run_task(&task_setup_data); |
| 569 | if (IS_ERR(task)) | 614 | if (IS_ERR(task)) |
| 570 | return PTR_ERR(task); | 615 | return PTR_ERR(task); |
| 571 | status = task->tk_status; | 616 | status = task->tk_status; |
| 572 | rpc_put_task(task); | 617 | rpc_put_task(task); |
| 573 | return status; | 618 | return status; |
| 574 | } | 619 | } |
| 620 | EXPORT_SYMBOL_GPL(rpc_call_sync); | ||
| 575 | 621 | ||
| 576 | /** | 622 | /** |
| 577 | * rpc_call_async - Perform an asynchronous RPC call | 623 | * rpc_call_async - Perform an asynchronous RPC call |
| @@ -586,45 +632,28 @@ rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags, | |||
| 586 | const struct rpc_call_ops *tk_ops, void *data) | 632 | const struct rpc_call_ops *tk_ops, void *data) |
| 587 | { | 633 | { |
| 588 | struct rpc_task *task; | 634 | struct rpc_task *task; |
| 635 | struct rpc_task_setup task_setup_data = { | ||
| 636 | .rpc_client = clnt, | ||
| 637 | .rpc_message = msg, | ||
| 638 | .callback_ops = tk_ops, | ||
| 639 | .callback_data = data, | ||
| 640 | .flags = flags|RPC_TASK_ASYNC, | ||
| 641 | }; | ||
| 589 | 642 | ||
| 590 | task = rpc_do_run_task(clnt, msg, flags|RPC_TASK_ASYNC, tk_ops, data); | 643 | task = rpc_run_task(&task_setup_data); |
| 591 | if (IS_ERR(task)) | 644 | if (IS_ERR(task)) |
| 592 | return PTR_ERR(task); | 645 | return PTR_ERR(task); |
| 593 | rpc_put_task(task); | 646 | rpc_put_task(task); |
| 594 | return 0; | 647 | return 0; |
| 595 | } | 648 | } |
| 596 | 649 | EXPORT_SYMBOL_GPL(rpc_call_async); | |
| 597 | /** | ||
| 598 | * rpc_run_task - Allocate a new RPC task, then run rpc_execute against it | ||
| 599 | * @clnt: pointer to RPC client | ||
| 600 | * @flags: RPC flags | ||
| 601 | * @ops: RPC call ops | ||
| 602 | * @data: user call data | ||
| 603 | */ | ||
| 604 | struct rpc_task *rpc_run_task(struct rpc_clnt *clnt, int flags, | ||
| 605 | const struct rpc_call_ops *tk_ops, | ||
| 606 | void *data) | ||
| 607 | { | ||
| 608 | return rpc_do_run_task(clnt, NULL, flags, tk_ops, data); | ||
| 609 | } | ||
| 610 | EXPORT_SYMBOL(rpc_run_task); | ||
| 611 | 650 | ||
| 612 | void | 651 | void |
| 613 | rpc_call_setup(struct rpc_task *task, struct rpc_message *msg, int flags) | 652 | rpc_call_start(struct rpc_task *task) |
| 614 | { | 653 | { |
| 615 | task->tk_msg = *msg; | 654 | task->tk_action = call_start; |
| 616 | task->tk_flags |= flags; | ||
| 617 | /* Bind the user cred */ | ||
| 618 | if (task->tk_msg.rpc_cred != NULL) | ||
| 619 | rpcauth_holdcred(task); | ||
| 620 | else | ||
| 621 | rpcauth_bindcred(task); | ||
| 622 | |||
| 623 | if (task->tk_status == 0) | ||
| 624 | task->tk_action = call_start; | ||
| 625 | else | ||
| 626 | task->tk_action = rpc_exit_task; | ||
| 627 | } | 655 | } |
| 656 | EXPORT_SYMBOL_GPL(rpc_call_start); | ||
| 628 | 657 | ||
| 629 | /** | 658 | /** |
| 630 | * rpc_peeraddr - extract remote peer address from clnt's xprt | 659 | * rpc_peeraddr - extract remote peer address from clnt's xprt |
| @@ -653,7 +682,8 @@ EXPORT_SYMBOL_GPL(rpc_peeraddr); | |||
| 653 | * @format: address format | 682 | * @format: address format |
| 654 | * | 683 | * |
| 655 | */ | 684 | */ |
| 656 | char *rpc_peeraddr2str(struct rpc_clnt *clnt, enum rpc_display_format_t format) | 685 | const char *rpc_peeraddr2str(struct rpc_clnt *clnt, |
| 686 | enum rpc_display_format_t format) | ||
| 657 | { | 687 | { |
| 658 | struct rpc_xprt *xprt = clnt->cl_xprt; | 688 | struct rpc_xprt *xprt = clnt->cl_xprt; |
| 659 | 689 | ||
| @@ -671,6 +701,7 @@ rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize | |||
| 671 | if (xprt->ops->set_buffer_size) | 701 | if (xprt->ops->set_buffer_size) |
| 672 | xprt->ops->set_buffer_size(xprt, sndsize, rcvsize); | 702 | xprt->ops->set_buffer_size(xprt, sndsize, rcvsize); |
| 673 | } | 703 | } |
| 704 | EXPORT_SYMBOL_GPL(rpc_setbufsize); | ||
| 674 | 705 | ||
| 675 | /* | 706 | /* |
| 676 | * Return size of largest payload RPC client can support, in bytes | 707 | * Return size of largest payload RPC client can support, in bytes |
| @@ -710,6 +741,7 @@ rpc_restart_call(struct rpc_task *task) | |||
| 710 | 741 | ||
| 711 | task->tk_action = call_start; | 742 | task->tk_action = call_start; |
| 712 | } | 743 | } |
| 744 | EXPORT_SYMBOL_GPL(rpc_restart_call); | ||
| 713 | 745 | ||
| 714 | /* | 746 | /* |
| 715 | * 0. Initial state | 747 | * 0. Initial state |
| @@ -1137,7 +1169,7 @@ call_status(struct rpc_task *task) | |||
| 1137 | case -ETIMEDOUT: | 1169 | case -ETIMEDOUT: |
| 1138 | task->tk_action = call_timeout; | 1170 | task->tk_action = call_timeout; |
| 1139 | if (task->tk_client->cl_discrtry) | 1171 | if (task->tk_client->cl_discrtry) |
| 1140 | xprt_disconnect(task->tk_xprt); | 1172 | xprt_force_disconnect(task->tk_xprt); |
| 1141 | break; | 1173 | break; |
| 1142 | case -ECONNREFUSED: | 1174 | case -ECONNREFUSED: |
| 1143 | case -ENOTCONN: | 1175 | case -ENOTCONN: |
| @@ -1260,7 +1292,7 @@ out_retry: | |||
| 1260 | req->rq_received = req->rq_private_buf.len = 0; | 1292 | req->rq_received = req->rq_private_buf.len = 0; |
| 1261 | task->tk_status = 0; | 1293 | task->tk_status = 0; |
| 1262 | if (task->tk_client->cl_discrtry) | 1294 | if (task->tk_client->cl_discrtry) |
| 1263 | xprt_disconnect(task->tk_xprt); | 1295 | xprt_force_disconnect(task->tk_xprt); |
| 1264 | } | 1296 | } |
| 1265 | 1297 | ||
| 1266 | /* | 1298 | /* |
| @@ -1517,9 +1549,15 @@ struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, int | |||
| 1517 | .rpc_proc = &rpcproc_null, | 1549 | .rpc_proc = &rpcproc_null, |
| 1518 | .rpc_cred = cred, | 1550 | .rpc_cred = cred, |
| 1519 | }; | 1551 | }; |
| 1520 | return rpc_do_run_task(clnt, &msg, flags, &rpc_default_ops, NULL); | 1552 | struct rpc_task_setup task_setup_data = { |
| 1553 | .rpc_client = clnt, | ||
| 1554 | .rpc_message = &msg, | ||
| 1555 | .callback_ops = &rpc_default_ops, | ||
| 1556 | .flags = flags, | ||
| 1557 | }; | ||
| 1558 | return rpc_run_task(&task_setup_data); | ||
| 1521 | } | 1559 | } |
| 1522 | EXPORT_SYMBOL(rpc_call_null); | 1560 | EXPORT_SYMBOL_GPL(rpc_call_null); |
| 1523 | 1561 | ||
| 1524 | #ifdef RPC_DEBUG | 1562 | #ifdef RPC_DEBUG |
| 1525 | void rpc_show_tasks(void) | 1563 | void rpc_show_tasks(void) |
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index c59f3ca2b41b..7e197168a245 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c | |||
| @@ -76,6 +76,16 @@ rpc_timeout_upcall_queue(struct work_struct *work) | |||
| 76 | rpc_purge_list(rpci, &free_list, destroy_msg, -ETIMEDOUT); | 76 | rpc_purge_list(rpci, &free_list, destroy_msg, -ETIMEDOUT); |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | /** | ||
| 80 | * rpc_queue_upcall | ||
| 81 | * @inode: inode of upcall pipe on which to queue given message | ||
| 82 | * @msg: message to queue | ||
| 83 | * | ||
| 84 | * Call with an @inode created by rpc_mkpipe() to queue an upcall. | ||
| 85 | * A userspace process may then later read the upcall by performing a | ||
| 86 | * read on an open file for this inode. It is up to the caller to | ||
| 87 | * initialize the fields of @msg (other than @msg->list) appropriately. | ||
| 88 | */ | ||
| 79 | int | 89 | int |
| 80 | rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg) | 90 | rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg) |
| 81 | { | 91 | { |
| @@ -103,6 +113,7 @@ out: | |||
| 103 | wake_up(&rpci->waitq); | 113 | wake_up(&rpci->waitq); |
| 104 | return res; | 114 | return res; |
| 105 | } | 115 | } |
| 116 | EXPORT_SYMBOL(rpc_queue_upcall); | ||
| 106 | 117 | ||
| 107 | static inline void | 118 | static inline void |
| 108 | rpc_inode_setowner(struct inode *inode, void *private) | 119 | rpc_inode_setowner(struct inode *inode, void *private) |
| @@ -512,8 +523,8 @@ rpc_get_inode(struct super_block *sb, int mode) | |||
| 512 | /* | 523 | /* |
| 513 | * FIXME: This probably has races. | 524 | * FIXME: This probably has races. |
| 514 | */ | 525 | */ |
| 515 | static void | 526 | static void rpc_depopulate(struct dentry *parent, |
| 516 | rpc_depopulate(struct dentry *parent, int start, int eof) | 527 | unsigned long start, unsigned long eof) |
| 517 | { | 528 | { |
| 518 | struct inode *dir = parent->d_inode; | 529 | struct inode *dir = parent->d_inode; |
| 519 | struct list_head *pos, *next; | 530 | struct list_head *pos, *next; |
| @@ -663,7 +674,16 @@ rpc_lookup_negative(char *path, struct nameidata *nd) | |||
| 663 | return dentry; | 674 | return dentry; |
| 664 | } | 675 | } |
| 665 | 676 | ||
| 666 | 677 | /** | |
| 678 | * rpc_mkdir - Create a new directory in rpc_pipefs | ||
| 679 | * @path: path from the rpc_pipefs root to the new directory | ||
| 680 | * @rpc_clnt: rpc client to associate with this directory | ||
| 681 | * | ||
| 682 | * This creates a directory at the given @path associated with | ||
| 683 | * @rpc_clnt, which will contain a file named "info" with some basic | ||
| 684 | * information about the client, together with any "pipes" that may | ||
| 685 | * later be created using rpc_mkpipe(). | ||
| 686 | */ | ||
| 667 | struct dentry * | 687 | struct dentry * |
| 668 | rpc_mkdir(char *path, struct rpc_clnt *rpc_client) | 688 | rpc_mkdir(char *path, struct rpc_clnt *rpc_client) |
| 669 | { | 689 | { |
| @@ -699,6 +719,10 @@ err_dput: | |||
| 699 | goto out; | 719 | goto out; |
| 700 | } | 720 | } |
| 701 | 721 | ||
| 722 | /** | ||
| 723 | * rpc_rmdir - Remove a directory created with rpc_mkdir() | ||
| 724 | * @dentry: directory to remove | ||
| 725 | */ | ||
| 702 | int | 726 | int |
| 703 | rpc_rmdir(struct dentry *dentry) | 727 | rpc_rmdir(struct dentry *dentry) |
| 704 | { | 728 | { |
| @@ -717,6 +741,25 @@ rpc_rmdir(struct dentry *dentry) | |||
| 717 | return error; | 741 | return error; |
| 718 | } | 742 | } |
| 719 | 743 | ||
| 744 | /** | ||
| 745 | * rpc_mkpipe - make an rpc_pipefs file for kernel<->userspace communication | ||
| 746 | * @parent: dentry of directory to create new "pipe" in | ||
| 747 | * @name: name of pipe | ||
| 748 | * @private: private data to associate with the pipe, for the caller's use | ||
| 749 | * @ops: operations defining the behavior of the pipe: upcall, downcall, | ||
| 750 | * release_pipe, and destroy_msg. | ||
| 751 | * | ||
| 752 | * Data is made available for userspace to read by calls to | ||
| 753 | * rpc_queue_upcall(). The actual reads will result in calls to | ||
| 754 | * @ops->upcall, which will be called with the file pointer, | ||
| 755 | * message, and userspace buffer to copy to. | ||
| 756 | * | ||
| 757 | * Writes can come at any time, and do not necessarily have to be | ||
| 758 | * responses to upcalls. They will result in calls to @msg->downcall. | ||
| 759 | * | ||
| 760 | * The @private argument passed here will be available to all these methods | ||
| 761 | * from the file pointer, via RPC_I(file->f_dentry->d_inode)->private. | ||
| 762 | */ | ||
| 720 | struct dentry * | 763 | struct dentry * |
| 721 | rpc_mkpipe(struct dentry *parent, const char *name, void *private, struct rpc_pipe_ops *ops, int flags) | 764 | rpc_mkpipe(struct dentry *parent, const char *name, void *private, struct rpc_pipe_ops *ops, int flags) |
| 722 | { | 765 | { |
| @@ -763,7 +806,16 @@ err_dput: | |||
| 763 | -ENOMEM); | 806 | -ENOMEM); |
| 764 | goto out; | 807 | goto out; |
| 765 | } | 808 | } |
| 809 | EXPORT_SYMBOL(rpc_mkpipe); | ||
| 766 | 810 | ||
| 811 | /** | ||
| 812 | * rpc_unlink - remove a pipe | ||
| 813 | * @dentry: dentry for the pipe, as returned from rpc_mkpipe | ||
| 814 | * | ||
| 815 | * After this call, lookups will no longer find the pipe, and any | ||
| 816 | * attempts to read or write using preexisting opens of the pipe will | ||
| 817 | * return -EPIPE. | ||
| 818 | */ | ||
| 767 | int | 819 | int |
| 768 | rpc_unlink(struct dentry *dentry) | 820 | rpc_unlink(struct dentry *dentry) |
| 769 | { | 821 | { |
| @@ -785,6 +837,7 @@ rpc_unlink(struct dentry *dentry) | |||
| 785 | dput(parent); | 837 | dput(parent); |
| 786 | return error; | 838 | return error; |
| 787 | } | 839 | } |
| 840 | EXPORT_SYMBOL(rpc_unlink); | ||
| 788 | 841 | ||
| 789 | /* | 842 | /* |
| 790 | * populate the filesystem | 843 | * populate the filesystem |
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index a05493aedb68..fa5b8f202d5b 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c | |||
| @@ -55,45 +55,6 @@ enum { | |||
| 55 | #define RPCB_HIGHPROC_4 RPCBPROC_GETSTAT | 55 | #define RPCB_HIGHPROC_4 RPCBPROC_GETSTAT |
| 56 | 56 | ||
| 57 | /* | 57 | /* |
| 58 | * r_addr | ||
| 59 | * | ||
| 60 | * Quoting RFC 3530, section 2.2: | ||
| 61 | * | ||
| 62 | * For TCP over IPv4 and for UDP over IPv4, the format of r_addr is the | ||
| 63 | * US-ASCII string: | ||
| 64 | * | ||
| 65 | * h1.h2.h3.h4.p1.p2 | ||
| 66 | * | ||
| 67 | * The prefix, "h1.h2.h3.h4", is the standard textual form for | ||
| 68 | * representing an IPv4 address, which is always four octets long. | ||
| 69 | * Assuming big-endian ordering, h1, h2, h3, and h4, are respectively, | ||
| 70 | * the first through fourth octets each converted to ASCII-decimal. | ||
| 71 | * Assuming big-endian ordering, p1 and p2 are, respectively, the first | ||
| 72 | * and second octets each converted to ASCII-decimal. For example, if a | ||
| 73 | * host, in big-endian order, has an address of 0x0A010307 and there is | ||
| 74 | * a service listening on, in big endian order, port 0x020F (decimal | ||
| 75 | * 527), then the complete universal address is "10.1.3.7.2.15". | ||
| 76 | * | ||
| 77 | * ... | ||
| 78 | * | ||
| 79 | * For TCP over IPv6 and for UDP over IPv6, the format of r_addr is the | ||
| 80 | * US-ASCII string: | ||
| 81 | * | ||
| 82 | * x1:x2:x3:x4:x5:x6:x7:x8.p1.p2 | ||
| 83 | * | ||
| 84 | * The suffix "p1.p2" is the service port, and is computed the same way | ||
| 85 | * as with universal addresses for TCP and UDP over IPv4. The prefix, | ||
| 86 | * "x1:x2:x3:x4:x5:x6:x7:x8", is the standard textual form for | ||
| 87 | * representing an IPv6 address as defined in Section 2.2 of [RFC2373]. | ||
| 88 | * Additionally, the two alternative forms specified in Section 2.2 of | ||
| 89 | * [RFC2373] are also acceptable. | ||
| 90 | * | ||
| 91 | * XXX: Currently this implementation does not explicitly convert the | ||
| 92 | * stored address to US-ASCII on non-ASCII systems. | ||
| 93 | */ | ||
| 94 | #define RPCB_MAXADDRLEN (128u) | ||
| 95 | |||
| 96 | /* | ||
| 97 | * r_owner | 58 | * r_owner |
| 98 | * | 59 | * |
| 99 | * The "owner" is allowed to unset a service in the rpcbind database. | 60 | * The "owner" is allowed to unset a service in the rpcbind database. |
| @@ -112,9 +73,9 @@ struct rpcbind_args { | |||
| 112 | u32 r_vers; | 73 | u32 r_vers; |
| 113 | u32 r_prot; | 74 | u32 r_prot; |
| 114 | unsigned short r_port; | 75 | unsigned short r_port; |
| 115 | char * r_netid; | 76 | const char * r_netid; |
| 116 | char r_addr[RPCB_MAXADDRLEN]; | 77 | const char * r_addr; |
| 117 | char * r_owner; | 78 | const char * r_owner; |
| 118 | }; | 79 | }; |
| 119 | 80 | ||
| 120 | static struct rpc_procinfo rpcb_procedures2[]; | 81 | static struct rpc_procinfo rpcb_procedures2[]; |
| @@ -128,19 +89,6 @@ struct rpcb_info { | |||
| 128 | static struct rpcb_info rpcb_next_version[]; | 89 | static struct rpcb_info rpcb_next_version[]; |
| 129 | static struct rpcb_info rpcb_next_version6[]; | 90 | static struct rpcb_info rpcb_next_version6[]; |
| 130 | 91 | ||
| 131 | static void rpcb_getport_prepare(struct rpc_task *task, void *calldata) | ||
| 132 | { | ||
| 133 | struct rpcbind_args *map = calldata; | ||
| 134 | struct rpc_xprt *xprt = map->r_xprt; | ||
| 135 | struct rpc_message msg = { | ||
| 136 | .rpc_proc = rpcb_next_version[xprt->bind_index].rpc_proc, | ||
| 137 | .rpc_argp = map, | ||
| 138 | .rpc_resp = &map->r_port, | ||
| 139 | }; | ||
| 140 | |||
| 141 | rpc_call_setup(task, &msg, 0); | ||
| 142 | } | ||
| 143 | |||
| 144 | static void rpcb_map_release(void *data) | 92 | static void rpcb_map_release(void *data) |
| 145 | { | 93 | { |
| 146 | struct rpcbind_args *map = data; | 94 | struct rpcbind_args *map = data; |
| @@ -150,7 +98,6 @@ static void rpcb_map_release(void *data) | |||
| 150 | } | 98 | } |
| 151 | 99 | ||
| 152 | static const struct rpc_call_ops rpcb_getport_ops = { | 100 | static const struct rpc_call_ops rpcb_getport_ops = { |
| 153 | .rpc_call_prepare = rpcb_getport_prepare, | ||
| 154 | .rpc_call_done = rpcb_getport_done, | 101 | .rpc_call_done = rpcb_getport_done, |
| 155 | .rpc_release = rpcb_map_release, | 102 | .rpc_release = rpcb_map_release, |
| 156 | }; | 103 | }; |
| @@ -162,12 +109,13 @@ static void rpcb_wake_rpcbind_waiters(struct rpc_xprt *xprt, int status) | |||
| 162 | } | 109 | } |
| 163 | 110 | ||
| 164 | static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr, | 111 | static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr, |
| 165 | int proto, int version, int privileged) | 112 | size_t salen, int proto, u32 version, |
| 113 | int privileged) | ||
| 166 | { | 114 | { |
| 167 | struct rpc_create_args args = { | 115 | struct rpc_create_args args = { |
| 168 | .protocol = proto, | 116 | .protocol = proto, |
| 169 | .address = srvaddr, | 117 | .address = srvaddr, |
| 170 | .addrsize = sizeof(struct sockaddr_in), | 118 | .addrsize = salen, |
| 171 | .servername = hostname, | 119 | .servername = hostname, |
| 172 | .program = &rpcb_program, | 120 | .program = &rpcb_program, |
| 173 | .version = version, | 121 | .version = version, |
| @@ -230,7 +178,7 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) | |||
| 230 | prog, vers, prot, port); | 178 | prog, vers, prot, port); |
| 231 | 179 | ||
| 232 | rpcb_clnt = rpcb_create("localhost", (struct sockaddr *) &sin, | 180 | rpcb_clnt = rpcb_create("localhost", (struct sockaddr *) &sin, |
| 233 | XPRT_TRANSPORT_UDP, 2, 1); | 181 | sizeof(sin), XPRT_TRANSPORT_UDP, 2, 1); |
| 234 | if (IS_ERR(rpcb_clnt)) | 182 | if (IS_ERR(rpcb_clnt)) |
| 235 | return PTR_ERR(rpcb_clnt); | 183 | return PTR_ERR(rpcb_clnt); |
| 236 | 184 | ||
| @@ -252,13 +200,15 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) | |||
| 252 | * @vers: RPC version number to bind | 200 | * @vers: RPC version number to bind |
| 253 | * @prot: transport protocol to use to make this request | 201 | * @prot: transport protocol to use to make this request |
| 254 | * | 202 | * |
| 203 | * Return value is the requested advertised port number, | ||
| 204 | * or a negative errno value. | ||
| 205 | * | ||
| 255 | * Called from outside the RPC client in a synchronous task context. | 206 | * Called from outside the RPC client in a synchronous task context. |
| 256 | * Uses default timeout parameters specified by underlying transport. | 207 | * Uses default timeout parameters specified by underlying transport. |
| 257 | * | 208 | * |
| 258 | * XXX: Needs to support IPv6, and rpcbind versions 3 and 4 | 209 | * XXX: Needs to support IPv6 |
| 259 | */ | 210 | */ |
| 260 | int rpcb_getport_sync(struct sockaddr_in *sin, __u32 prog, | 211 | int rpcb_getport_sync(struct sockaddr_in *sin, u32 prog, u32 vers, int prot) |
| 261 | __u32 vers, int prot) | ||
| 262 | { | 212 | { |
| 263 | struct rpcbind_args map = { | 213 | struct rpcbind_args map = { |
| 264 | .r_prog = prog, | 214 | .r_prog = prog, |
| @@ -272,14 +222,13 @@ int rpcb_getport_sync(struct sockaddr_in *sin, __u32 prog, | |||
| 272 | .rpc_resp = &map.r_port, | 222 | .rpc_resp = &map.r_port, |
| 273 | }; | 223 | }; |
| 274 | struct rpc_clnt *rpcb_clnt; | 224 | struct rpc_clnt *rpcb_clnt; |
| 275 | char hostname[40]; | ||
| 276 | int status; | 225 | int status; |
| 277 | 226 | ||
| 278 | dprintk("RPC: %s(" NIPQUAD_FMT ", %u, %u, %d)\n", | 227 | dprintk("RPC: %s(" NIPQUAD_FMT ", %u, %u, %d)\n", |
| 279 | __FUNCTION__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot); | 228 | __FUNCTION__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot); |
| 280 | 229 | ||
| 281 | sprintf(hostname, NIPQUAD_FMT, NIPQUAD(sin->sin_addr.s_addr)); | 230 | rpcb_clnt = rpcb_create(NULL, (struct sockaddr *)sin, |
| 282 | rpcb_clnt = rpcb_create(hostname, (struct sockaddr *)sin, prot, 2, 0); | 231 | sizeof(*sin), prot, 2, 0); |
| 283 | if (IS_ERR(rpcb_clnt)) | 232 | if (IS_ERR(rpcb_clnt)) |
| 284 | return PTR_ERR(rpcb_clnt); | 233 | return PTR_ERR(rpcb_clnt); |
| 285 | 234 | ||
| @@ -295,6 +244,24 @@ int rpcb_getport_sync(struct sockaddr_in *sin, __u32 prog, | |||
| 295 | } | 244 | } |
| 296 | EXPORT_SYMBOL_GPL(rpcb_getport_sync); | 245 | EXPORT_SYMBOL_GPL(rpcb_getport_sync); |
| 297 | 246 | ||
| 247 | static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbind_args *map, int version) | ||
| 248 | { | ||
| 249 | struct rpc_message msg = { | ||
| 250 | .rpc_proc = rpcb_next_version[version].rpc_proc, | ||
| 251 | .rpc_argp = map, | ||
| 252 | .rpc_resp = &map->r_port, | ||
| 253 | }; | ||
| 254 | struct rpc_task_setup task_setup_data = { | ||
| 255 | .rpc_client = rpcb_clnt, | ||
| 256 | .rpc_message = &msg, | ||
| 257 | .callback_ops = &rpcb_getport_ops, | ||
| 258 | .callback_data = map, | ||
| 259 | .flags = RPC_TASK_ASYNC, | ||
| 260 | }; | ||
| 261 | |||
| 262 | return rpc_run_task(&task_setup_data); | ||
| 263 | } | ||
| 264 | |||
| 298 | /** | 265 | /** |
| 299 | * rpcb_getport_async - obtain the port for a given RPC service on a given host | 266 | * rpcb_getport_async - obtain the port for a given RPC service on a given host |
| 300 | * @task: task that is waiting for portmapper request | 267 | * @task: task that is waiting for portmapper request |
| @@ -305,12 +272,14 @@ EXPORT_SYMBOL_GPL(rpcb_getport_sync); | |||
| 305 | void rpcb_getport_async(struct rpc_task *task) | 272 | void rpcb_getport_async(struct rpc_task *task) |
| 306 | { | 273 | { |
| 307 | struct rpc_clnt *clnt = task->tk_client; | 274 | struct rpc_clnt *clnt = task->tk_client; |
| 308 | int bind_version; | 275 | u32 bind_version; |
| 309 | struct rpc_xprt *xprt = task->tk_xprt; | 276 | struct rpc_xprt *xprt = task->tk_xprt; |
| 310 | struct rpc_clnt *rpcb_clnt; | 277 | struct rpc_clnt *rpcb_clnt; |
| 311 | static struct rpcbind_args *map; | 278 | static struct rpcbind_args *map; |
| 312 | struct rpc_task *child; | 279 | struct rpc_task *child; |
| 313 | struct sockaddr addr; | 280 | struct sockaddr_storage addr; |
| 281 | struct sockaddr *sap = (struct sockaddr *)&addr; | ||
| 282 | size_t salen; | ||
| 314 | int status; | 283 | int status; |
| 315 | struct rpcb_info *info; | 284 | struct rpcb_info *info; |
| 316 | 285 | ||
| @@ -340,10 +309,10 @@ void rpcb_getport_async(struct rpc_task *task) | |||
| 340 | goto bailout_nofree; | 309 | goto bailout_nofree; |
| 341 | } | 310 | } |
| 342 | 311 | ||
| 343 | rpc_peeraddr(clnt, (void *)&addr, sizeof(addr)); | 312 | salen = rpc_peeraddr(clnt, sap, sizeof(addr)); |
| 344 | 313 | ||
| 345 | /* Don't ever use rpcbind v2 for AF_INET6 requests */ | 314 | /* Don't ever use rpcbind v2 for AF_INET6 requests */ |
| 346 | switch (addr.sa_family) { | 315 | switch (sap->sa_family) { |
| 347 | case AF_INET: | 316 | case AF_INET: |
| 348 | info = rpcb_next_version; | 317 | info = rpcb_next_version; |
| 349 | break; | 318 | break; |
| @@ -368,7 +337,7 @@ void rpcb_getport_async(struct rpc_task *task) | |||
| 368 | dprintk("RPC: %5u %s: trying rpcbind version %u\n", | 337 | dprintk("RPC: %5u %s: trying rpcbind version %u\n", |
| 369 | task->tk_pid, __FUNCTION__, bind_version); | 338 | task->tk_pid, __FUNCTION__, bind_version); |
| 370 | 339 | ||
| 371 | rpcb_clnt = rpcb_create(clnt->cl_server, &addr, xprt->prot, | 340 | rpcb_clnt = rpcb_create(clnt->cl_server, sap, salen, xprt->prot, |
| 372 | bind_version, 0); | 341 | bind_version, 0); |
| 373 | if (IS_ERR(rpcb_clnt)) { | 342 | if (IS_ERR(rpcb_clnt)) { |
| 374 | status = PTR_ERR(rpcb_clnt); | 343 | status = PTR_ERR(rpcb_clnt); |
| @@ -390,12 +359,10 @@ void rpcb_getport_async(struct rpc_task *task) | |||
| 390 | map->r_port = 0; | 359 | map->r_port = 0; |
| 391 | map->r_xprt = xprt_get(xprt); | 360 | map->r_xprt = xprt_get(xprt); |
| 392 | map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID); | 361 | map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID); |
| 393 | memcpy(map->r_addr, | 362 | map->r_addr = rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR); |
| 394 | rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR), | ||
| 395 | sizeof(map->r_addr)); | ||
| 396 | map->r_owner = RPCB_OWNER_STRING; /* ignored for GETADDR */ | 363 | map->r_owner = RPCB_OWNER_STRING; /* ignored for GETADDR */ |
| 397 | 364 | ||
| 398 | child = rpc_run_task(rpcb_clnt, RPC_TASK_ASYNC, &rpcb_getport_ops, map); | 365 | child = rpcb_call_async(rpcb_clnt, map, xprt->bind_index); |
| 399 | rpc_release_client(rpcb_clnt); | 366 | rpc_release_client(rpcb_clnt); |
| 400 | if (IS_ERR(child)) { | 367 | if (IS_ERR(child)) { |
| 401 | status = -EIO; | 368 | status = -EIO; |
| @@ -518,7 +485,7 @@ static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p, | |||
| 518 | * Simple sanity check. The smallest possible universal | 485 | * Simple sanity check. The smallest possible universal |
| 519 | * address is an IPv4 address string containing 11 bytes. | 486 | * address is an IPv4 address string containing 11 bytes. |
| 520 | */ | 487 | */ |
| 521 | if (addr_len < 11 || addr_len > RPCB_MAXADDRLEN) | 488 | if (addr_len < 11 || addr_len > RPCBIND_MAXUADDRLEN) |
| 522 | goto out_err; | 489 | goto out_err; |
| 523 | 490 | ||
| 524 | /* | 491 | /* |
| @@ -569,7 +536,7 @@ out_err: | |||
| 569 | #define RPCB_boolean_sz (1u) | 536 | #define RPCB_boolean_sz (1u) |
| 570 | 537 | ||
| 571 | #define RPCB_netid_sz (1+XDR_QUADLEN(RPCBIND_MAXNETIDLEN)) | 538 | #define RPCB_netid_sz (1+XDR_QUADLEN(RPCBIND_MAXNETIDLEN)) |
| 572 | #define RPCB_addr_sz (1+XDR_QUADLEN(RPCB_MAXADDRLEN)) | 539 | #define RPCB_addr_sz (1+XDR_QUADLEN(RPCBIND_MAXUADDRLEN)) |
| 573 | #define RPCB_ownerstring_sz (1+XDR_QUADLEN(RPCB_MAXOWNERLEN)) | 540 | #define RPCB_ownerstring_sz (1+XDR_QUADLEN(RPCB_MAXOWNERLEN)) |
| 574 | 541 | ||
| 575 | #define RPCB_mappingargs_sz RPCB_program_sz+RPCB_version_sz+ \ | 542 | #define RPCB_mappingargs_sz RPCB_program_sz+RPCB_version_sz+ \ |
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index eed5dd9819cd..40ce6f6672d6 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
| @@ -45,7 +45,7 @@ static void rpc_release_task(struct rpc_task *task); | |||
| 45 | /* | 45 | /* |
| 46 | * RPC tasks sit here while waiting for conditions to improve. | 46 | * RPC tasks sit here while waiting for conditions to improve. |
| 47 | */ | 47 | */ |
| 48 | static RPC_WAITQ(delay_queue, "delayq"); | 48 | static struct rpc_wait_queue delay_queue; |
| 49 | 49 | ||
| 50 | /* | 50 | /* |
| 51 | * rpciod-related stuff | 51 | * rpciod-related stuff |
| @@ -135,7 +135,7 @@ static void __rpc_add_wait_queue_priority(struct rpc_wait_queue *queue, struct r | |||
| 135 | if (unlikely(task->tk_priority > queue->maxpriority)) | 135 | if (unlikely(task->tk_priority > queue->maxpriority)) |
| 136 | q = &queue->tasks[queue->maxpriority]; | 136 | q = &queue->tasks[queue->maxpriority]; |
| 137 | list_for_each_entry(t, q, u.tk_wait.list) { | 137 | list_for_each_entry(t, q, u.tk_wait.list) { |
| 138 | if (t->tk_cookie == task->tk_cookie) { | 138 | if (t->tk_owner == task->tk_owner) { |
| 139 | list_add_tail(&task->u.tk_wait.list, &t->u.tk_wait.links); | 139 | list_add_tail(&task->u.tk_wait.list, &t->u.tk_wait.links); |
| 140 | return; | 140 | return; |
| 141 | } | 141 | } |
| @@ -208,26 +208,26 @@ static inline void rpc_set_waitqueue_priority(struct rpc_wait_queue *queue, int | |||
| 208 | queue->count = 1 << (priority * 2); | 208 | queue->count = 1 << (priority * 2); |
| 209 | } | 209 | } |
| 210 | 210 | ||
| 211 | static inline void rpc_set_waitqueue_cookie(struct rpc_wait_queue *queue, unsigned long cookie) | 211 | static inline void rpc_set_waitqueue_owner(struct rpc_wait_queue *queue, pid_t pid) |
| 212 | { | 212 | { |
| 213 | queue->cookie = cookie; | 213 | queue->owner = pid; |
| 214 | queue->nr = RPC_BATCH_COUNT; | 214 | queue->nr = RPC_BATCH_COUNT; |
| 215 | } | 215 | } |
| 216 | 216 | ||
| 217 | static inline void rpc_reset_waitqueue_priority(struct rpc_wait_queue *queue) | 217 | static inline void rpc_reset_waitqueue_priority(struct rpc_wait_queue *queue) |
| 218 | { | 218 | { |
| 219 | rpc_set_waitqueue_priority(queue, queue->maxpriority); | 219 | rpc_set_waitqueue_priority(queue, queue->maxpriority); |
| 220 | rpc_set_waitqueue_cookie(queue, 0); | 220 | rpc_set_waitqueue_owner(queue, 0); |
| 221 | } | 221 | } |
| 222 | 222 | ||
| 223 | static void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname, int maxprio) | 223 | static void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname, unsigned char nr_queues) |
| 224 | { | 224 | { |
| 225 | int i; | 225 | int i; |
| 226 | 226 | ||
| 227 | spin_lock_init(&queue->lock); | 227 | spin_lock_init(&queue->lock); |
| 228 | for (i = 0; i < ARRAY_SIZE(queue->tasks); i++) | 228 | for (i = 0; i < ARRAY_SIZE(queue->tasks); i++) |
| 229 | INIT_LIST_HEAD(&queue->tasks[i]); | 229 | INIT_LIST_HEAD(&queue->tasks[i]); |
| 230 | queue->maxpriority = maxprio; | 230 | queue->maxpriority = nr_queues - 1; |
| 231 | rpc_reset_waitqueue_priority(queue); | 231 | rpc_reset_waitqueue_priority(queue); |
| 232 | #ifdef RPC_DEBUG | 232 | #ifdef RPC_DEBUG |
| 233 | queue->name = qname; | 233 | queue->name = qname; |
| @@ -236,14 +236,14 @@ static void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const c | |||
| 236 | 236 | ||
| 237 | void rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname) | 237 | void rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname) |
| 238 | { | 238 | { |
| 239 | __rpc_init_priority_wait_queue(queue, qname, RPC_PRIORITY_HIGH); | 239 | __rpc_init_priority_wait_queue(queue, qname, RPC_NR_PRIORITY); |
| 240 | } | 240 | } |
| 241 | 241 | ||
| 242 | void rpc_init_wait_queue(struct rpc_wait_queue *queue, const char *qname) | 242 | void rpc_init_wait_queue(struct rpc_wait_queue *queue, const char *qname) |
| 243 | { | 243 | { |
| 244 | __rpc_init_priority_wait_queue(queue, qname, 0); | 244 | __rpc_init_priority_wait_queue(queue, qname, 1); |
| 245 | } | 245 | } |
| 246 | EXPORT_SYMBOL(rpc_init_wait_queue); | 246 | EXPORT_SYMBOL_GPL(rpc_init_wait_queue); |
| 247 | 247 | ||
| 248 | static int rpc_wait_bit_interruptible(void *word) | 248 | static int rpc_wait_bit_interruptible(void *word) |
| 249 | { | 249 | { |
| @@ -303,7 +303,7 @@ int __rpc_wait_for_completion_task(struct rpc_task *task, int (*action)(void *)) | |||
| 303 | return wait_on_bit(&task->tk_runstate, RPC_TASK_ACTIVE, | 303 | return wait_on_bit(&task->tk_runstate, RPC_TASK_ACTIVE, |
| 304 | action, TASK_INTERRUPTIBLE); | 304 | action, TASK_INTERRUPTIBLE); |
| 305 | } | 305 | } |
| 306 | EXPORT_SYMBOL(__rpc_wait_for_completion_task); | 306 | EXPORT_SYMBOL_GPL(__rpc_wait_for_completion_task); |
| 307 | 307 | ||
| 308 | /* | 308 | /* |
| 309 | * Make an RPC task runnable. | 309 | * Make an RPC task runnable. |
| @@ -373,6 +373,7 @@ void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, | |||
| 373 | __rpc_sleep_on(q, task, action, timer); | 373 | __rpc_sleep_on(q, task, action, timer); |
| 374 | spin_unlock_bh(&q->lock); | 374 | spin_unlock_bh(&q->lock); |
| 375 | } | 375 | } |
| 376 | EXPORT_SYMBOL_GPL(rpc_sleep_on); | ||
| 376 | 377 | ||
| 377 | /** | 378 | /** |
| 378 | * __rpc_do_wake_up_task - wake up a single rpc_task | 379 | * __rpc_do_wake_up_task - wake up a single rpc_task |
| @@ -444,6 +445,7 @@ void rpc_wake_up_task(struct rpc_task *task) | |||
| 444 | } | 445 | } |
| 445 | rcu_read_unlock_bh(); | 446 | rcu_read_unlock_bh(); |
| 446 | } | 447 | } |
| 448 | EXPORT_SYMBOL_GPL(rpc_wake_up_task); | ||
| 447 | 449 | ||
| 448 | /* | 450 | /* |
| 449 | * Wake up the next task on a priority queue. | 451 | * Wake up the next task on a priority queue. |
| @@ -454,12 +456,12 @@ static struct rpc_task * __rpc_wake_up_next_priority(struct rpc_wait_queue *queu | |||
| 454 | struct rpc_task *task; | 456 | struct rpc_task *task; |
| 455 | 457 | ||
| 456 | /* | 458 | /* |
| 457 | * Service a batch of tasks from a single cookie. | 459 | * Service a batch of tasks from a single owner. |
| 458 | */ | 460 | */ |
| 459 | q = &queue->tasks[queue->priority]; | 461 | q = &queue->tasks[queue->priority]; |
| 460 | if (!list_empty(q)) { | 462 | if (!list_empty(q)) { |
| 461 | task = list_entry(q->next, struct rpc_task, u.tk_wait.list); | 463 | task = list_entry(q->next, struct rpc_task, u.tk_wait.list); |
| 462 | if (queue->cookie == task->tk_cookie) { | 464 | if (queue->owner == task->tk_owner) { |
| 463 | if (--queue->nr) | 465 | if (--queue->nr) |
| 464 | goto out; | 466 | goto out; |
| 465 | list_move_tail(&task->u.tk_wait.list, q); | 467 | list_move_tail(&task->u.tk_wait.list, q); |
| @@ -468,7 +470,7 @@ static struct rpc_task * __rpc_wake_up_next_priority(struct rpc_wait_queue *queu | |||
| 468 | * Check if we need to switch queues. | 470 | * Check if we need to switch queues. |
| 469 | */ | 471 | */ |
| 470 | if (--queue->count) | 472 | if (--queue->count) |
| 471 | goto new_cookie; | 473 | goto new_owner; |
| 472 | } | 474 | } |
| 473 | 475 | ||
| 474 | /* | 476 | /* |
| @@ -490,8 +492,8 @@ static struct rpc_task * __rpc_wake_up_next_priority(struct rpc_wait_queue *queu | |||
| 490 | 492 | ||
| 491 | new_queue: | 493 | new_queue: |
| 492 | rpc_set_waitqueue_priority(queue, (unsigned int)(q - &queue->tasks[0])); | 494 | rpc_set_waitqueue_priority(queue, (unsigned int)(q - &queue->tasks[0])); |
| 493 | new_cookie: | 495 | new_owner: |
| 494 | rpc_set_waitqueue_cookie(queue, task->tk_cookie); | 496 | rpc_set_waitqueue_owner(queue, task->tk_owner); |
| 495 | out: | 497 | out: |
| 496 | __rpc_wake_up_task(task); | 498 | __rpc_wake_up_task(task); |
| 497 | return task; | 499 | return task; |
| @@ -519,6 +521,7 @@ struct rpc_task * rpc_wake_up_next(struct rpc_wait_queue *queue) | |||
| 519 | 521 | ||
| 520 | return task; | 522 | return task; |
| 521 | } | 523 | } |
| 524 | EXPORT_SYMBOL_GPL(rpc_wake_up_next); | ||
| 522 | 525 | ||
| 523 | /** | 526 | /** |
| 524 | * rpc_wake_up - wake up all rpc_tasks | 527 | * rpc_wake_up - wake up all rpc_tasks |
| @@ -544,6 +547,7 @@ void rpc_wake_up(struct rpc_wait_queue *queue) | |||
| 544 | spin_unlock(&queue->lock); | 547 | spin_unlock(&queue->lock); |
| 545 | rcu_read_unlock_bh(); | 548 | rcu_read_unlock_bh(); |
| 546 | } | 549 | } |
| 550 | EXPORT_SYMBOL_GPL(rpc_wake_up); | ||
| 547 | 551 | ||
| 548 | /** | 552 | /** |
| 549 | * rpc_wake_up_status - wake up all rpc_tasks and set their status value. | 553 | * rpc_wake_up_status - wake up all rpc_tasks and set their status value. |
| @@ -572,6 +576,7 @@ void rpc_wake_up_status(struct rpc_wait_queue *queue, int status) | |||
| 572 | spin_unlock(&queue->lock); | 576 | spin_unlock(&queue->lock); |
| 573 | rcu_read_unlock_bh(); | 577 | rcu_read_unlock_bh(); |
| 574 | } | 578 | } |
| 579 | EXPORT_SYMBOL_GPL(rpc_wake_up_status); | ||
| 575 | 580 | ||
| 576 | static void __rpc_atrun(struct rpc_task *task) | 581 | static void __rpc_atrun(struct rpc_task *task) |
| 577 | { | 582 | { |
| @@ -586,6 +591,7 @@ void rpc_delay(struct rpc_task *task, unsigned long delay) | |||
| 586 | task->tk_timeout = delay; | 591 | task->tk_timeout = delay; |
| 587 | rpc_sleep_on(&delay_queue, task, NULL, __rpc_atrun); | 592 | rpc_sleep_on(&delay_queue, task, NULL, __rpc_atrun); |
| 588 | } | 593 | } |
| 594 | EXPORT_SYMBOL_GPL(rpc_delay); | ||
| 589 | 595 | ||
| 590 | /* | 596 | /* |
| 591 | * Helper to call task->tk_ops->rpc_call_prepare | 597 | * Helper to call task->tk_ops->rpc_call_prepare |
| @@ -614,7 +620,7 @@ void rpc_exit_task(struct rpc_task *task) | |||
| 614 | } | 620 | } |
| 615 | } | 621 | } |
| 616 | } | 622 | } |
| 617 | EXPORT_SYMBOL(rpc_exit_task); | 623 | EXPORT_SYMBOL_GPL(rpc_exit_task); |
| 618 | 624 | ||
| 619 | void rpc_release_calldata(const struct rpc_call_ops *ops, void *calldata) | 625 | void rpc_release_calldata(const struct rpc_call_ops *ops, void *calldata) |
| 620 | { | 626 | { |
| @@ -808,39 +814,49 @@ EXPORT_SYMBOL_GPL(rpc_free); | |||
| 808 | /* | 814 | /* |
| 809 | * Creation and deletion of RPC task structures | 815 | * Creation and deletion of RPC task structures |
| 810 | */ | 816 | */ |
| 811 | void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, int flags, const struct rpc_call_ops *tk_ops, void *calldata) | 817 | static void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *task_setup_data) |
| 812 | { | 818 | { |
| 813 | memset(task, 0, sizeof(*task)); | 819 | memset(task, 0, sizeof(*task)); |
| 814 | setup_timer(&task->tk_timer, (void (*)(unsigned long))rpc_run_timer, | 820 | setup_timer(&task->tk_timer, (void (*)(unsigned long))rpc_run_timer, |
| 815 | (unsigned long)task); | 821 | (unsigned long)task); |
| 816 | atomic_set(&task->tk_count, 1); | 822 | atomic_set(&task->tk_count, 1); |
| 817 | task->tk_client = clnt; | 823 | task->tk_flags = task_setup_data->flags; |
| 818 | task->tk_flags = flags; | 824 | task->tk_ops = task_setup_data->callback_ops; |
| 819 | task->tk_ops = tk_ops; | 825 | task->tk_calldata = task_setup_data->callback_data; |
| 820 | if (tk_ops->rpc_call_prepare != NULL) | ||
| 821 | task->tk_action = rpc_prepare_task; | ||
| 822 | task->tk_calldata = calldata; | ||
| 823 | INIT_LIST_HEAD(&task->tk_task); | 826 | INIT_LIST_HEAD(&task->tk_task); |
| 824 | 827 | ||
| 825 | /* Initialize retry counters */ | 828 | /* Initialize retry counters */ |
| 826 | task->tk_garb_retry = 2; | 829 | task->tk_garb_retry = 2; |
| 827 | task->tk_cred_retry = 2; | 830 | task->tk_cred_retry = 2; |
| 828 | 831 | ||
| 829 | task->tk_priority = RPC_PRIORITY_NORMAL; | 832 | task->tk_priority = task_setup_data->priority - RPC_PRIORITY_LOW; |
| 830 | task->tk_cookie = (unsigned long)current; | 833 | task->tk_owner = current->tgid; |
| 831 | 834 | ||
| 832 | /* Initialize workqueue for async tasks */ | 835 | /* Initialize workqueue for async tasks */ |
| 833 | task->tk_workqueue = rpciod_workqueue; | 836 | task->tk_workqueue = rpciod_workqueue; |
| 834 | 837 | ||
| 835 | if (clnt) { | 838 | task->tk_client = task_setup_data->rpc_client; |
| 836 | kref_get(&clnt->cl_kref); | 839 | if (task->tk_client != NULL) { |
| 837 | if (clnt->cl_softrtry) | 840 | kref_get(&task->tk_client->cl_kref); |
| 841 | if (task->tk_client->cl_softrtry) | ||
| 838 | task->tk_flags |= RPC_TASK_SOFT; | 842 | task->tk_flags |= RPC_TASK_SOFT; |
| 839 | if (!clnt->cl_intr) | 843 | if (!task->tk_client->cl_intr) |
| 840 | task->tk_flags |= RPC_TASK_NOINTR; | 844 | task->tk_flags |= RPC_TASK_NOINTR; |
| 841 | } | 845 | } |
| 842 | 846 | ||
| 843 | BUG_ON(task->tk_ops == NULL); | 847 | if (task->tk_ops->rpc_call_prepare != NULL) |
| 848 | task->tk_action = rpc_prepare_task; | ||
| 849 | |||
| 850 | if (task_setup_data->rpc_message != NULL) { | ||
| 851 | memcpy(&task->tk_msg, task_setup_data->rpc_message, sizeof(task->tk_msg)); | ||
| 852 | /* Bind the user cred */ | ||
| 853 | if (task->tk_msg.rpc_cred != NULL) | ||
| 854 | rpcauth_holdcred(task); | ||
| 855 | else | ||
| 856 | rpcauth_bindcred(task); | ||
| 857 | if (task->tk_action == NULL) | ||
| 858 | rpc_call_start(task); | ||
| 859 | } | ||
| 844 | 860 | ||
| 845 | /* starting timestamp */ | 861 | /* starting timestamp */ |
| 846 | task->tk_start = jiffies; | 862 | task->tk_start = jiffies; |
| @@ -865,18 +881,22 @@ static void rpc_free_task(struct rcu_head *rcu) | |||
| 865 | /* | 881 | /* |
| 866 | * Create a new task for the specified client. | 882 | * Create a new task for the specified client. |
| 867 | */ | 883 | */ |
| 868 | struct rpc_task *rpc_new_task(struct rpc_clnt *clnt, int flags, const struct rpc_call_ops *tk_ops, void *calldata) | 884 | struct rpc_task *rpc_new_task(const struct rpc_task_setup *setup_data) |
| 869 | { | 885 | { |
| 870 | struct rpc_task *task; | 886 | struct rpc_task *task = setup_data->task; |
| 871 | 887 | unsigned short flags = 0; | |
| 872 | task = rpc_alloc_task(); | 888 | |
| 873 | if (!task) | 889 | if (task == NULL) { |
| 874 | goto out; | 890 | task = rpc_alloc_task(); |
| 891 | if (task == NULL) | ||
| 892 | goto out; | ||
| 893 | flags = RPC_TASK_DYNAMIC; | ||
| 894 | } | ||
| 875 | 895 | ||
| 876 | rpc_init_task(task, clnt, flags, tk_ops, calldata); | 896 | rpc_init_task(task, setup_data); |
| 877 | 897 | ||
| 898 | task->tk_flags |= flags; | ||
| 878 | dprintk("RPC: allocated task %p\n", task); | 899 | dprintk("RPC: allocated task %p\n", task); |
| 879 | task->tk_flags |= RPC_TASK_DYNAMIC; | ||
| 880 | out: | 900 | out: |
| 881 | return task; | 901 | return task; |
| 882 | } | 902 | } |
| @@ -902,7 +922,7 @@ void rpc_put_task(struct rpc_task *task) | |||
| 902 | call_rcu_bh(&task->u.tk_rcu, rpc_free_task); | 922 | call_rcu_bh(&task->u.tk_rcu, rpc_free_task); |
| 903 | rpc_release_calldata(tk_ops, calldata); | 923 | rpc_release_calldata(tk_ops, calldata); |
| 904 | } | 924 | } |
| 905 | EXPORT_SYMBOL(rpc_put_task); | 925 | EXPORT_SYMBOL_GPL(rpc_put_task); |
| 906 | 926 | ||
| 907 | static void rpc_release_task(struct rpc_task *task) | 927 | static void rpc_release_task(struct rpc_task *task) |
| 908 | { | 928 | { |
| @@ -959,6 +979,7 @@ void rpc_killall_tasks(struct rpc_clnt *clnt) | |||
| 959 | } | 979 | } |
| 960 | spin_unlock(&clnt->cl_lock); | 980 | spin_unlock(&clnt->cl_lock); |
| 961 | } | 981 | } |
| 982 | EXPORT_SYMBOL_GPL(rpc_killall_tasks); | ||
| 962 | 983 | ||
| 963 | int rpciod_up(void) | 984 | int rpciod_up(void) |
| 964 | { | 985 | { |
| @@ -1038,6 +1059,11 @@ rpc_init_mempool(void) | |||
| 1038 | goto err_nomem; | 1059 | goto err_nomem; |
| 1039 | if (!rpciod_start()) | 1060 | if (!rpciod_start()) |
| 1040 | goto err_nomem; | 1061 | goto err_nomem; |
| 1062 | /* | ||
| 1063 | * The following is not strictly a mempool initialisation, | ||
| 1064 | * but there is no harm in doing it here | ||
| 1065 | */ | ||
| 1066 | rpc_init_wait_queue(&delay_queue, "delayq"); | ||
| 1041 | return 0; | 1067 | return 0; |
| 1042 | err_nomem: | 1068 | err_nomem: |
| 1043 | rpc_destroy_mempool(); | 1069 | rpc_destroy_mempool(); |
diff --git a/net/sunrpc/socklib.c b/net/sunrpc/socklib.c index 97ac45f034d6..a661a3acb37e 100644 --- a/net/sunrpc/socklib.c +++ b/net/sunrpc/socklib.c | |||
| @@ -72,7 +72,7 @@ ssize_t xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, struct | |||
| 72 | struct page **ppage = xdr->pages; | 72 | struct page **ppage = xdr->pages; |
| 73 | unsigned int len, pglen = xdr->page_len; | 73 | unsigned int len, pglen = xdr->page_len; |
| 74 | ssize_t copied = 0; | 74 | ssize_t copied = 0; |
| 75 | int ret; | 75 | size_t ret; |
| 76 | 76 | ||
| 77 | len = xdr->head[0].iov_len; | 77 | len = xdr->head[0].iov_len; |
| 78 | if (base < len) { | 78 | if (base < len) { |
diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c index 4d4f3738b688..74df2d358e61 100644 --- a/net/sunrpc/stats.c +++ b/net/sunrpc/stats.c | |||
| @@ -118,7 +118,7 @@ struct rpc_iostats *rpc_alloc_iostats(struct rpc_clnt *clnt) | |||
| 118 | new = kcalloc(clnt->cl_maxproc, sizeof(struct rpc_iostats), GFP_KERNEL); | 118 | new = kcalloc(clnt->cl_maxproc, sizeof(struct rpc_iostats), GFP_KERNEL); |
| 119 | return new; | 119 | return new; |
| 120 | } | 120 | } |
| 121 | EXPORT_SYMBOL(rpc_alloc_iostats); | 121 | EXPORT_SYMBOL_GPL(rpc_alloc_iostats); |
| 122 | 122 | ||
| 123 | /** | 123 | /** |
| 124 | * rpc_free_iostats - release an rpc_iostats structure | 124 | * rpc_free_iostats - release an rpc_iostats structure |
| @@ -129,7 +129,7 @@ void rpc_free_iostats(struct rpc_iostats *stats) | |||
| 129 | { | 129 | { |
| 130 | kfree(stats); | 130 | kfree(stats); |
| 131 | } | 131 | } |
| 132 | EXPORT_SYMBOL(rpc_free_iostats); | 132 | EXPORT_SYMBOL_GPL(rpc_free_iostats); |
| 133 | 133 | ||
| 134 | /** | 134 | /** |
| 135 | * rpc_count_iostats - tally up per-task stats | 135 | * rpc_count_iostats - tally up per-task stats |
| @@ -215,7 +215,7 @@ void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt) | |||
| 215 | metrics->om_execute * MILLISECS_PER_JIFFY); | 215 | metrics->om_execute * MILLISECS_PER_JIFFY); |
| 216 | } | 216 | } |
| 217 | } | 217 | } |
| 218 | EXPORT_SYMBOL(rpc_print_iostats); | 218 | EXPORT_SYMBOL_GPL(rpc_print_iostats); |
| 219 | 219 | ||
| 220 | /* | 220 | /* |
| 221 | * Register/unregister RPC proc files | 221 | * Register/unregister RPC proc files |
| @@ -241,12 +241,14 @@ rpc_proc_register(struct rpc_stat *statp) | |||
| 241 | { | 241 | { |
| 242 | return do_register(statp->program->name, statp, &rpc_proc_fops); | 242 | return do_register(statp->program->name, statp, &rpc_proc_fops); |
| 243 | } | 243 | } |
| 244 | EXPORT_SYMBOL_GPL(rpc_proc_register); | ||
| 244 | 245 | ||
| 245 | void | 246 | void |
| 246 | rpc_proc_unregister(const char *name) | 247 | rpc_proc_unregister(const char *name) |
| 247 | { | 248 | { |
| 248 | remove_proc_entry(name, proc_net_rpc); | 249 | remove_proc_entry(name, proc_net_rpc); |
| 249 | } | 250 | } |
| 251 | EXPORT_SYMBOL_GPL(rpc_proc_unregister); | ||
| 250 | 252 | ||
| 251 | struct proc_dir_entry * | 253 | struct proc_dir_entry * |
| 252 | svc_proc_register(struct svc_stat *statp, const struct file_operations *fops) | 254 | svc_proc_register(struct svc_stat *statp, const struct file_operations *fops) |
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 33d89e842c85..1a7e309d008b 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c | |||
| @@ -22,45 +22,6 @@ | |||
| 22 | #include <linux/sunrpc/rpc_pipe_fs.h> | 22 | #include <linux/sunrpc/rpc_pipe_fs.h> |
| 23 | #include <linux/sunrpc/xprtsock.h> | 23 | #include <linux/sunrpc/xprtsock.h> |
| 24 | 24 | ||
| 25 | /* RPC scheduler */ | ||
| 26 | EXPORT_SYMBOL(rpc_execute); | ||
| 27 | EXPORT_SYMBOL(rpc_init_task); | ||
| 28 | EXPORT_SYMBOL(rpc_sleep_on); | ||
| 29 | EXPORT_SYMBOL(rpc_wake_up_next); | ||
| 30 | EXPORT_SYMBOL(rpc_wake_up_task); | ||
| 31 | EXPORT_SYMBOL(rpc_wake_up_status); | ||
| 32 | |||
| 33 | /* RPC client functions */ | ||
| 34 | EXPORT_SYMBOL(rpc_clone_client); | ||
| 35 | EXPORT_SYMBOL(rpc_bind_new_program); | ||
| 36 | EXPORT_SYMBOL(rpc_shutdown_client); | ||
| 37 | EXPORT_SYMBOL(rpc_killall_tasks); | ||
| 38 | EXPORT_SYMBOL(rpc_call_sync); | ||
| 39 | EXPORT_SYMBOL(rpc_call_async); | ||
| 40 | EXPORT_SYMBOL(rpc_call_setup); | ||
| 41 | EXPORT_SYMBOL(rpc_clnt_sigmask); | ||
| 42 | EXPORT_SYMBOL(rpc_clnt_sigunmask); | ||
| 43 | EXPORT_SYMBOL(rpc_delay); | ||
| 44 | EXPORT_SYMBOL(rpc_restart_call); | ||
| 45 | EXPORT_SYMBOL(rpc_setbufsize); | ||
| 46 | EXPORT_SYMBOL(rpc_unlink); | ||
| 47 | EXPORT_SYMBOL(rpc_wake_up); | ||
| 48 | EXPORT_SYMBOL(rpc_queue_upcall); | ||
| 49 | EXPORT_SYMBOL(rpc_mkpipe); | ||
| 50 | |||
| 51 | /* Client transport */ | ||
| 52 | EXPORT_SYMBOL(xprt_set_timeout); | ||
| 53 | |||
| 54 | /* Client credential cache */ | ||
| 55 | EXPORT_SYMBOL(rpcauth_register); | ||
| 56 | EXPORT_SYMBOL(rpcauth_unregister); | ||
| 57 | EXPORT_SYMBOL(rpcauth_create); | ||
| 58 | EXPORT_SYMBOL(rpcauth_lookupcred); | ||
| 59 | EXPORT_SYMBOL(rpcauth_lookup_credcache); | ||
| 60 | EXPORT_SYMBOL(rpcauth_destroy_credcache); | ||
| 61 | EXPORT_SYMBOL(rpcauth_init_credcache); | ||
| 62 | EXPORT_SYMBOL(put_rpccred); | ||
| 63 | |||
| 64 | /* RPC server stuff */ | 25 | /* RPC server stuff */ |
| 65 | EXPORT_SYMBOL(svc_create); | 26 | EXPORT_SYMBOL(svc_create); |
| 66 | EXPORT_SYMBOL(svc_create_thread); | 27 | EXPORT_SYMBOL(svc_create_thread); |
| @@ -81,8 +42,6 @@ EXPORT_SYMBOL(svc_set_client); | |||
| 81 | 42 | ||
| 82 | /* RPC statistics */ | 43 | /* RPC statistics */ |
| 83 | #ifdef CONFIG_PROC_FS | 44 | #ifdef CONFIG_PROC_FS |
| 84 | EXPORT_SYMBOL(rpc_proc_register); | ||
| 85 | EXPORT_SYMBOL(rpc_proc_unregister); | ||
| 86 | EXPORT_SYMBOL(svc_proc_register); | 45 | EXPORT_SYMBOL(svc_proc_register); |
| 87 | EXPORT_SYMBOL(svc_proc_unregister); | 46 | EXPORT_SYMBOL(svc_proc_unregister); |
| 88 | EXPORT_SYMBOL(svc_seq_show); | 47 | EXPORT_SYMBOL(svc_seq_show); |
| @@ -105,31 +64,6 @@ EXPORT_SYMBOL(qword_get); | |||
| 105 | EXPORT_SYMBOL(svcauth_unix_purge); | 64 | EXPORT_SYMBOL(svcauth_unix_purge); |
| 106 | EXPORT_SYMBOL(unix_domain_find); | 65 | EXPORT_SYMBOL(unix_domain_find); |
| 107 | 66 | ||
| 108 | /* Generic XDR */ | ||
| 109 | EXPORT_SYMBOL(xdr_encode_string); | ||
| 110 | EXPORT_SYMBOL(xdr_decode_string_inplace); | ||
| 111 | EXPORT_SYMBOL(xdr_decode_netobj); | ||
| 112 | EXPORT_SYMBOL(xdr_encode_netobj); | ||
| 113 | EXPORT_SYMBOL(xdr_encode_pages); | ||
| 114 | EXPORT_SYMBOL(xdr_inline_pages); | ||
| 115 | EXPORT_SYMBOL(xdr_shift_buf); | ||
| 116 | EXPORT_SYMBOL(xdr_encode_word); | ||
| 117 | EXPORT_SYMBOL(xdr_decode_word); | ||
| 118 | EXPORT_SYMBOL(xdr_encode_array2); | ||
| 119 | EXPORT_SYMBOL(xdr_decode_array2); | ||
| 120 | EXPORT_SYMBOL(xdr_buf_from_iov); | ||
| 121 | EXPORT_SYMBOL(xdr_buf_subsegment); | ||
| 122 | EXPORT_SYMBOL(xdr_buf_read_netobj); | ||
| 123 | EXPORT_SYMBOL(read_bytes_from_xdr_buf); | ||
| 124 | |||
| 125 | /* Debugging symbols */ | ||
| 126 | #ifdef RPC_DEBUG | ||
| 127 | EXPORT_SYMBOL(rpc_debug); | ||
| 128 | EXPORT_SYMBOL(nfs_debug); | ||
| 129 | EXPORT_SYMBOL(nfsd_debug); | ||
| 130 | EXPORT_SYMBOL(nlm_debug); | ||
| 131 | #endif | ||
| 132 | |||
| 133 | extern struct cache_detail ip_map_cache, unix_gid_cache; | 67 | extern struct cache_detail ip_map_cache, unix_gid_cache; |
| 134 | 68 | ||
| 135 | static int __init | 69 | static int __init |
diff --git a/net/sunrpc/sysctl.c b/net/sunrpc/sysctl.c index 2be714e9b382..bada7de0c2fc 100644 --- a/net/sunrpc/sysctl.c +++ b/net/sunrpc/sysctl.c | |||
| @@ -23,9 +23,16 @@ | |||
| 23 | * Declare the debug flags here | 23 | * Declare the debug flags here |
| 24 | */ | 24 | */ |
| 25 | unsigned int rpc_debug; | 25 | unsigned int rpc_debug; |
| 26 | EXPORT_SYMBOL_GPL(rpc_debug); | ||
| 27 | |||
| 26 | unsigned int nfs_debug; | 28 | unsigned int nfs_debug; |
| 29 | EXPORT_SYMBOL_GPL(nfs_debug); | ||
| 30 | |||
| 27 | unsigned int nfsd_debug; | 31 | unsigned int nfsd_debug; |
| 32 | EXPORT_SYMBOL_GPL(nfsd_debug); | ||
| 33 | |||
| 28 | unsigned int nlm_debug; | 34 | unsigned int nlm_debug; |
| 35 | EXPORT_SYMBOL_GPL(nlm_debug); | ||
| 29 | 36 | ||
| 30 | #ifdef RPC_DEBUG | 37 | #ifdef RPC_DEBUG |
| 31 | 38 | ||
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index fdc5e6d7562b..54264062ea69 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c | |||
| @@ -28,6 +28,7 @@ xdr_encode_netobj(__be32 *p, const struct xdr_netobj *obj) | |||
| 28 | memcpy(p, obj->data, obj->len); | 28 | memcpy(p, obj->data, obj->len); |
| 29 | return p + XDR_QUADLEN(obj->len); | 29 | return p + XDR_QUADLEN(obj->len); |
| 30 | } | 30 | } |
| 31 | EXPORT_SYMBOL(xdr_encode_netobj); | ||
| 31 | 32 | ||
| 32 | __be32 * | 33 | __be32 * |
| 33 | xdr_decode_netobj(__be32 *p, struct xdr_netobj *obj) | 34 | xdr_decode_netobj(__be32 *p, struct xdr_netobj *obj) |
| @@ -40,6 +41,7 @@ xdr_decode_netobj(__be32 *p, struct xdr_netobj *obj) | |||
| 40 | obj->data = (u8 *) p; | 41 | obj->data = (u8 *) p; |
| 41 | return p + XDR_QUADLEN(len); | 42 | return p + XDR_QUADLEN(len); |
| 42 | } | 43 | } |
| 44 | EXPORT_SYMBOL(xdr_decode_netobj); | ||
| 43 | 45 | ||
| 44 | /** | 46 | /** |
| 45 | * xdr_encode_opaque_fixed - Encode fixed length opaque data | 47 | * xdr_encode_opaque_fixed - Encode fixed length opaque data |
| @@ -91,6 +93,7 @@ xdr_encode_string(__be32 *p, const char *string) | |||
| 91 | { | 93 | { |
| 92 | return xdr_encode_array(p, string, strlen(string)); | 94 | return xdr_encode_array(p, string, strlen(string)); |
| 93 | } | 95 | } |
| 96 | EXPORT_SYMBOL(xdr_encode_string); | ||
| 94 | 97 | ||
| 95 | __be32 * | 98 | __be32 * |
| 96 | xdr_decode_string_inplace(__be32 *p, char **sp, int *lenp, int maxlen) | 99 | xdr_decode_string_inplace(__be32 *p, char **sp, int *lenp, int maxlen) |
| @@ -103,6 +106,7 @@ xdr_decode_string_inplace(__be32 *p, char **sp, int *lenp, int maxlen) | |||
| 103 | *sp = (char *) p; | 106 | *sp = (char *) p; |
| 104 | return p + XDR_QUADLEN(len); | 107 | return p + XDR_QUADLEN(len); |
| 105 | } | 108 | } |
| 109 | EXPORT_SYMBOL(xdr_decode_string_inplace); | ||
| 106 | 110 | ||
| 107 | void | 111 | void |
| 108 | xdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base, | 112 | xdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base, |
| @@ -130,6 +134,7 @@ xdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base, | |||
| 130 | xdr->buflen += len; | 134 | xdr->buflen += len; |
| 131 | xdr->len += len; | 135 | xdr->len += len; |
| 132 | } | 136 | } |
| 137 | EXPORT_SYMBOL(xdr_encode_pages); | ||
| 133 | 138 | ||
| 134 | void | 139 | void |
| 135 | xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset, | 140 | xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset, |
| @@ -151,7 +156,7 @@ xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset, | |||
| 151 | 156 | ||
| 152 | xdr->buflen += len; | 157 | xdr->buflen += len; |
| 153 | } | 158 | } |
| 154 | 159 | EXPORT_SYMBOL(xdr_inline_pages); | |
| 155 | 160 | ||
| 156 | /* | 161 | /* |
| 157 | * Helper routines for doing 'memmove' like operations on a struct xdr_buf | 162 | * Helper routines for doing 'memmove' like operations on a struct xdr_buf |
| @@ -418,6 +423,7 @@ xdr_shift_buf(struct xdr_buf *buf, size_t len) | |||
| 418 | { | 423 | { |
| 419 | xdr_shrink_bufhead(buf, len); | 424 | xdr_shrink_bufhead(buf, len); |
| 420 | } | 425 | } |
| 426 | EXPORT_SYMBOL(xdr_shift_buf); | ||
| 421 | 427 | ||
| 422 | /** | 428 | /** |
| 423 | * xdr_init_encode - Initialize a struct xdr_stream for sending data. | 429 | * xdr_init_encode - Initialize a struct xdr_stream for sending data. |
| @@ -639,6 +645,7 @@ xdr_buf_from_iov(struct kvec *iov, struct xdr_buf *buf) | |||
| 639 | buf->page_len = 0; | 645 | buf->page_len = 0; |
| 640 | buf->buflen = buf->len = iov->iov_len; | 646 | buf->buflen = buf->len = iov->iov_len; |
| 641 | } | 647 | } |
| 648 | EXPORT_SYMBOL(xdr_buf_from_iov); | ||
| 642 | 649 | ||
| 643 | /* Sets subbuf to the portion of buf of length len beginning base bytes | 650 | /* Sets subbuf to the portion of buf of length len beginning base bytes |
| 644 | * from the start of buf. Returns -1 if base of length are out of bounds. */ | 651 | * from the start of buf. Returns -1 if base of length are out of bounds. */ |
| @@ -687,6 +694,7 @@ xdr_buf_subsegment(struct xdr_buf *buf, struct xdr_buf *subbuf, | |||
| 687 | return -1; | 694 | return -1; |
| 688 | return 0; | 695 | return 0; |
| 689 | } | 696 | } |
| 697 | EXPORT_SYMBOL(xdr_buf_subsegment); | ||
| 690 | 698 | ||
| 691 | static void __read_bytes_from_xdr_buf(struct xdr_buf *subbuf, void *obj, unsigned int len) | 699 | static void __read_bytes_from_xdr_buf(struct xdr_buf *subbuf, void *obj, unsigned int len) |
| 692 | { | 700 | { |
| @@ -717,6 +725,7 @@ int read_bytes_from_xdr_buf(struct xdr_buf *buf, unsigned int base, void *obj, u | |||
| 717 | __read_bytes_from_xdr_buf(&subbuf, obj, len); | 725 | __read_bytes_from_xdr_buf(&subbuf, obj, len); |
| 718 | return 0; | 726 | return 0; |
| 719 | } | 727 | } |
| 728 | EXPORT_SYMBOL(read_bytes_from_xdr_buf); | ||
| 720 | 729 | ||
| 721 | static void __write_bytes_to_xdr_buf(struct xdr_buf *subbuf, void *obj, unsigned int len) | 730 | static void __write_bytes_to_xdr_buf(struct xdr_buf *subbuf, void *obj, unsigned int len) |
| 722 | { | 731 | { |
| @@ -760,6 +769,7 @@ xdr_decode_word(struct xdr_buf *buf, unsigned int base, u32 *obj) | |||
| 760 | *obj = ntohl(raw); | 769 | *obj = ntohl(raw); |
| 761 | return 0; | 770 | return 0; |
| 762 | } | 771 | } |
| 772 | EXPORT_SYMBOL(xdr_decode_word); | ||
| 763 | 773 | ||
| 764 | int | 774 | int |
| 765 | xdr_encode_word(struct xdr_buf *buf, unsigned int base, u32 obj) | 775 | xdr_encode_word(struct xdr_buf *buf, unsigned int base, u32 obj) |
| @@ -768,6 +778,7 @@ xdr_encode_word(struct xdr_buf *buf, unsigned int base, u32 obj) | |||
| 768 | 778 | ||
| 769 | return write_bytes_to_xdr_buf(buf, base, &raw, sizeof(obj)); | 779 | return write_bytes_to_xdr_buf(buf, base, &raw, sizeof(obj)); |
| 770 | } | 780 | } |
| 781 | EXPORT_SYMBOL(xdr_encode_word); | ||
| 771 | 782 | ||
| 772 | /* If the netobj starting offset bytes from the start of xdr_buf is contained | 783 | /* If the netobj starting offset bytes from the start of xdr_buf is contained |
| 773 | * entirely in the head or the tail, set object to point to it; otherwise | 784 | * entirely in the head or the tail, set object to point to it; otherwise |
| @@ -805,6 +816,7 @@ int xdr_buf_read_netobj(struct xdr_buf *buf, struct xdr_netobj *obj, unsigned in | |||
| 805 | __read_bytes_from_xdr_buf(&subbuf, obj->data, obj->len); | 816 | __read_bytes_from_xdr_buf(&subbuf, obj->data, obj->len); |
| 806 | return 0; | 817 | return 0; |
| 807 | } | 818 | } |
| 819 | EXPORT_SYMBOL(xdr_buf_read_netobj); | ||
| 808 | 820 | ||
| 809 | /* Returns 0 on success, or else a negative error code. */ | 821 | /* Returns 0 on success, or else a negative error code. */ |
| 810 | static int | 822 | static int |
| @@ -1010,6 +1022,7 @@ xdr_decode_array2(struct xdr_buf *buf, unsigned int base, | |||
| 1010 | 1022 | ||
| 1011 | return xdr_xcode_array2(buf, base, desc, 0); | 1023 | return xdr_xcode_array2(buf, base, desc, 0); |
| 1012 | } | 1024 | } |
| 1025 | EXPORT_SYMBOL(xdr_decode_array2); | ||
| 1013 | 1026 | ||
| 1014 | int | 1027 | int |
| 1015 | xdr_encode_array2(struct xdr_buf *buf, unsigned int base, | 1028 | xdr_encode_array2(struct xdr_buf *buf, unsigned int base, |
| @@ -1021,6 +1034,7 @@ xdr_encode_array2(struct xdr_buf *buf, unsigned int base, | |||
| 1021 | 1034 | ||
| 1022 | return xdr_xcode_array2(buf, base, desc, 1); | 1035 | return xdr_xcode_array2(buf, base, desc, 1); |
| 1023 | } | 1036 | } |
| 1037 | EXPORT_SYMBOL(xdr_encode_array2); | ||
| 1024 | 1038 | ||
| 1025 | int | 1039 | int |
| 1026 | xdr_process_buf(struct xdr_buf *buf, unsigned int offset, unsigned int len, | 1040 | xdr_process_buf(struct xdr_buf *buf, unsigned int offset, unsigned int len, |
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index fb92f51405c5..cfcade906a56 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
| @@ -501,9 +501,10 @@ EXPORT_SYMBOL_GPL(xprt_set_retrans_timeout_def); | |||
| 501 | void xprt_set_retrans_timeout_rtt(struct rpc_task *task) | 501 | void xprt_set_retrans_timeout_rtt(struct rpc_task *task) |
| 502 | { | 502 | { |
| 503 | int timer = task->tk_msg.rpc_proc->p_timer; | 503 | int timer = task->tk_msg.rpc_proc->p_timer; |
| 504 | struct rpc_rtt *rtt = task->tk_client->cl_rtt; | 504 | struct rpc_clnt *clnt = task->tk_client; |
| 505 | struct rpc_rtt *rtt = clnt->cl_rtt; | ||
| 505 | struct rpc_rqst *req = task->tk_rqstp; | 506 | struct rpc_rqst *req = task->tk_rqstp; |
| 506 | unsigned long max_timeout = req->rq_xprt->timeout.to_maxval; | 507 | unsigned long max_timeout = clnt->cl_timeout->to_maxval; |
| 507 | 508 | ||
| 508 | task->tk_timeout = rpc_calc_rto(rtt, timer); | 509 | task->tk_timeout = rpc_calc_rto(rtt, timer); |
| 509 | task->tk_timeout <<= rpc_ntimeo(rtt, timer) + req->rq_retries; | 510 | task->tk_timeout <<= rpc_ntimeo(rtt, timer) + req->rq_retries; |
| @@ -514,7 +515,7 @@ EXPORT_SYMBOL_GPL(xprt_set_retrans_timeout_rtt); | |||
| 514 | 515 | ||
| 515 | static void xprt_reset_majortimeo(struct rpc_rqst *req) | 516 | static void xprt_reset_majortimeo(struct rpc_rqst *req) |
| 516 | { | 517 | { |
| 517 | struct rpc_timeout *to = &req->rq_xprt->timeout; | 518 | const struct rpc_timeout *to = req->rq_task->tk_client->cl_timeout; |
| 518 | 519 | ||
| 519 | req->rq_majortimeo = req->rq_timeout; | 520 | req->rq_majortimeo = req->rq_timeout; |
| 520 | if (to->to_exponential) | 521 | if (to->to_exponential) |
| @@ -534,7 +535,7 @@ static void xprt_reset_majortimeo(struct rpc_rqst *req) | |||
| 534 | int xprt_adjust_timeout(struct rpc_rqst *req) | 535 | int xprt_adjust_timeout(struct rpc_rqst *req) |
| 535 | { | 536 | { |
| 536 | struct rpc_xprt *xprt = req->rq_xprt; | 537 | struct rpc_xprt *xprt = req->rq_xprt; |
| 537 | struct rpc_timeout *to = &xprt->timeout; | 538 | const struct rpc_timeout *to = req->rq_task->tk_client->cl_timeout; |
| 538 | int status = 0; | 539 | int status = 0; |
| 539 | 540 | ||
| 540 | if (time_before(jiffies, req->rq_majortimeo)) { | 541 | if (time_before(jiffies, req->rq_majortimeo)) { |
| @@ -568,17 +569,17 @@ static void xprt_autoclose(struct work_struct *work) | |||
| 568 | struct rpc_xprt *xprt = | 569 | struct rpc_xprt *xprt = |
| 569 | container_of(work, struct rpc_xprt, task_cleanup); | 570 | container_of(work, struct rpc_xprt, task_cleanup); |
| 570 | 571 | ||
| 571 | xprt_disconnect(xprt); | ||
| 572 | xprt->ops->close(xprt); | 572 | xprt->ops->close(xprt); |
| 573 | clear_bit(XPRT_CLOSE_WAIT, &xprt->state); | ||
| 573 | xprt_release_write(xprt, NULL); | 574 | xprt_release_write(xprt, NULL); |
| 574 | } | 575 | } |
| 575 | 576 | ||
| 576 | /** | 577 | /** |
| 577 | * xprt_disconnect - mark a transport as disconnected | 578 | * xprt_disconnect_done - mark a transport as disconnected |
| 578 | * @xprt: transport to flag for disconnect | 579 | * @xprt: transport to flag for disconnect |
| 579 | * | 580 | * |
| 580 | */ | 581 | */ |
| 581 | void xprt_disconnect(struct rpc_xprt *xprt) | 582 | void xprt_disconnect_done(struct rpc_xprt *xprt) |
| 582 | { | 583 | { |
| 583 | dprintk("RPC: disconnected transport %p\n", xprt); | 584 | dprintk("RPC: disconnected transport %p\n", xprt); |
| 584 | spin_lock_bh(&xprt->transport_lock); | 585 | spin_lock_bh(&xprt->transport_lock); |
| @@ -586,7 +587,26 @@ void xprt_disconnect(struct rpc_xprt *xprt) | |||
| 586 | xprt_wake_pending_tasks(xprt, -ENOTCONN); | 587 | xprt_wake_pending_tasks(xprt, -ENOTCONN); |
| 587 | spin_unlock_bh(&xprt->transport_lock); | 588 | spin_unlock_bh(&xprt->transport_lock); |
| 588 | } | 589 | } |
| 589 | EXPORT_SYMBOL_GPL(xprt_disconnect); | 590 | EXPORT_SYMBOL_GPL(xprt_disconnect_done); |
| 591 | |||
| 592 | /** | ||
| 593 | * xprt_force_disconnect - force a transport to disconnect | ||
| 594 | * @xprt: transport to disconnect | ||
| 595 | * | ||
| 596 | */ | ||
| 597 | void xprt_force_disconnect(struct rpc_xprt *xprt) | ||
| 598 | { | ||
| 599 | /* Don't race with the test_bit() in xprt_clear_locked() */ | ||
| 600 | spin_lock_bh(&xprt->transport_lock); | ||
| 601 | set_bit(XPRT_CLOSE_WAIT, &xprt->state); | ||
| 602 | /* Try to schedule an autoclose RPC call */ | ||
| 603 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0) | ||
| 604 | queue_work(rpciod_workqueue, &xprt->task_cleanup); | ||
| 605 | else if (xprt->snd_task != NULL) | ||
| 606 | rpc_wake_up_task(xprt->snd_task); | ||
| 607 | spin_unlock_bh(&xprt->transport_lock); | ||
| 608 | } | ||
| 609 | EXPORT_SYMBOL_GPL(xprt_force_disconnect); | ||
| 590 | 610 | ||
| 591 | static void | 611 | static void |
| 592 | xprt_init_autodisconnect(unsigned long data) | 612 | xprt_init_autodisconnect(unsigned long data) |
| @@ -909,7 +929,7 @@ static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt) | |||
| 909 | { | 929 | { |
| 910 | struct rpc_rqst *req = task->tk_rqstp; | 930 | struct rpc_rqst *req = task->tk_rqstp; |
| 911 | 931 | ||
| 912 | req->rq_timeout = xprt->timeout.to_initval; | 932 | req->rq_timeout = task->tk_client->cl_timeout->to_initval; |
| 913 | req->rq_task = task; | 933 | req->rq_task = task; |
| 914 | req->rq_xprt = xprt; | 934 | req->rq_xprt = xprt; |
| 915 | req->rq_buffer = NULL; | 935 | req->rq_buffer = NULL; |
| @@ -959,22 +979,6 @@ void xprt_release(struct rpc_task *task) | |||
| 959 | } | 979 | } |
| 960 | 980 | ||
| 961 | /** | 981 | /** |
| 962 | * xprt_set_timeout - set constant RPC timeout | ||
| 963 | * @to: RPC timeout parameters to set up | ||
| 964 | * @retr: number of retries | ||
| 965 | * @incr: amount of increase after each retry | ||
| 966 | * | ||
| 967 | */ | ||
| 968 | void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long incr) | ||
| 969 | { | ||
| 970 | to->to_initval = | ||
| 971 | to->to_increment = incr; | ||
| 972 | to->to_maxval = to->to_initval + (incr * retr); | ||
| 973 | to->to_retries = retr; | ||
| 974 | to->to_exponential = 0; | ||
| 975 | } | ||
| 976 | |||
| 977 | /** | ||
| 978 | * xprt_create_transport - create an RPC transport | 982 | * xprt_create_transport - create an RPC transport |
| 979 | * @args: rpc transport creation arguments | 983 | * @args: rpc transport creation arguments |
| 980 | * | 984 | * |
diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c index 1aa1580cda6d..e55427f73dfe 100644 --- a/net/sunrpc/xprtrdma/rpc_rdma.c +++ b/net/sunrpc/xprtrdma/rpc_rdma.c | |||
| @@ -83,7 +83,7 @@ static const char transfertypes[][12] = { | |||
| 83 | */ | 83 | */ |
| 84 | 84 | ||
| 85 | static int | 85 | static int |
| 86 | rpcrdma_convert_iovs(struct xdr_buf *xdrbuf, int pos, | 86 | rpcrdma_convert_iovs(struct xdr_buf *xdrbuf, unsigned int pos, |
| 87 | enum rpcrdma_chunktype type, struct rpcrdma_mr_seg *seg, int nsegs) | 87 | enum rpcrdma_chunktype type, struct rpcrdma_mr_seg *seg, int nsegs) |
| 88 | { | 88 | { |
| 89 | int len, n = 0, p; | 89 | int len, n = 0, p; |
| @@ -169,7 +169,7 @@ rpcrdma_create_chunks(struct rpc_rqst *rqst, struct xdr_buf *target, | |||
| 169 | struct rpcrdma_req *req = rpcr_to_rdmar(rqst); | 169 | struct rpcrdma_req *req = rpcr_to_rdmar(rqst); |
| 170 | struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(rqst->rq_task->tk_xprt); | 170 | struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(rqst->rq_task->tk_xprt); |
| 171 | int nsegs, nchunks = 0; | 171 | int nsegs, nchunks = 0; |
| 172 | int pos; | 172 | unsigned int pos; |
| 173 | struct rpcrdma_mr_seg *seg = req->rl_segments; | 173 | struct rpcrdma_mr_seg *seg = req->rl_segments; |
| 174 | struct rpcrdma_read_chunk *cur_rchunk = NULL; | 174 | struct rpcrdma_read_chunk *cur_rchunk = NULL; |
| 175 | struct rpcrdma_write_array *warray = NULL; | 175 | struct rpcrdma_write_array *warray = NULL; |
| @@ -213,7 +213,7 @@ rpcrdma_create_chunks(struct rpc_rqst *rqst, struct xdr_buf *target, | |||
| 213 | (__be32 *)&cur_rchunk->rc_target.rs_offset, | 213 | (__be32 *)&cur_rchunk->rc_target.rs_offset, |
| 214 | seg->mr_base); | 214 | seg->mr_base); |
| 215 | dprintk("RPC: %s: read chunk " | 215 | dprintk("RPC: %s: read chunk " |
| 216 | "elem %d@0x%llx:0x%x pos %d (%s)\n", __func__, | 216 | "elem %d@0x%llx:0x%x pos %u (%s)\n", __func__, |
| 217 | seg->mr_len, (unsigned long long)seg->mr_base, | 217 | seg->mr_len, (unsigned long long)seg->mr_base, |
| 218 | seg->mr_rkey, pos, n < nsegs ? "more" : "last"); | 218 | seg->mr_rkey, pos, n < nsegs ? "more" : "last"); |
| 219 | cur_rchunk++; | 219 | cur_rchunk++; |
| @@ -552,7 +552,7 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst) | |||
| 552 | * RDMA'd by server. See map at rpcrdma_create_chunks()! :-) | 552 | * RDMA'd by server. See map at rpcrdma_create_chunks()! :-) |
| 553 | */ | 553 | */ |
| 554 | static int | 554 | static int |
| 555 | rpcrdma_count_chunks(struct rpcrdma_rep *rep, int max, int wrchunk, __be32 **iptrp) | 555 | rpcrdma_count_chunks(struct rpcrdma_rep *rep, unsigned int max, int wrchunk, __be32 **iptrp) |
| 556 | { | 556 | { |
| 557 | unsigned int i, total_len; | 557 | unsigned int i, total_len; |
| 558 | struct rpcrdma_write_chunk *cur_wchunk; | 558 | struct rpcrdma_write_chunk *cur_wchunk; |
diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index 6f2112dd9f78..02c522c17de5 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c | |||
| @@ -212,12 +212,16 @@ xprt_rdma_format_addresses(struct rpc_xprt *xprt) | |||
| 212 | static void | 212 | static void |
| 213 | xprt_rdma_free_addresses(struct rpc_xprt *xprt) | 213 | xprt_rdma_free_addresses(struct rpc_xprt *xprt) |
| 214 | { | 214 | { |
| 215 | kfree(xprt->address_strings[RPC_DISPLAY_ADDR]); | 215 | unsigned int i; |
| 216 | kfree(xprt->address_strings[RPC_DISPLAY_PORT]); | 216 | |
| 217 | kfree(xprt->address_strings[RPC_DISPLAY_ALL]); | 217 | for (i = 0; i < RPC_DISPLAY_MAX; i++) |
| 218 | kfree(xprt->address_strings[RPC_DISPLAY_HEX_ADDR]); | 218 | switch (i) { |
| 219 | kfree(xprt->address_strings[RPC_DISPLAY_HEX_PORT]); | 219 | case RPC_DISPLAY_PROTO: |
| 220 | kfree(xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR]); | 220 | case RPC_DISPLAY_NETID: |
| 221 | continue; | ||
| 222 | default: | ||
| 223 | kfree(xprt->address_strings[i]); | ||
| 224 | } | ||
| 221 | } | 225 | } |
| 222 | 226 | ||
| 223 | static void | 227 | static void |
| @@ -289,6 +293,11 @@ xprt_rdma_destroy(struct rpc_xprt *xprt) | |||
| 289 | module_put(THIS_MODULE); | 293 | module_put(THIS_MODULE); |
| 290 | } | 294 | } |
| 291 | 295 | ||
| 296 | static const struct rpc_timeout xprt_rdma_default_timeout = { | ||
| 297 | .to_initval = 60 * HZ, | ||
| 298 | .to_maxval = 60 * HZ, | ||
| 299 | }; | ||
| 300 | |||
| 292 | /** | 301 | /** |
| 293 | * xprt_setup_rdma - Set up transport to use RDMA | 302 | * xprt_setup_rdma - Set up transport to use RDMA |
| 294 | * | 303 | * |
| @@ -327,7 +336,7 @@ xprt_setup_rdma(struct xprt_create *args) | |||
| 327 | } | 336 | } |
| 328 | 337 | ||
| 329 | /* 60 second timeout, no retries */ | 338 | /* 60 second timeout, no retries */ |
| 330 | xprt_set_timeout(&xprt->timeout, 0, 60UL * HZ); | 339 | xprt->timeout = &xprt_rdma_default_timeout; |
| 331 | xprt->bind_timeout = (60U * HZ); | 340 | xprt->bind_timeout = (60U * HZ); |
| 332 | xprt->connect_timeout = (60U * HZ); | 341 | xprt->connect_timeout = (60U * HZ); |
| 333 | xprt->reestablish_timeout = (5U * HZ); | 342 | xprt->reestablish_timeout = (5U * HZ); |
| @@ -449,7 +458,7 @@ xprt_rdma_close(struct rpc_xprt *xprt) | |||
| 449 | struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt); | 458 | struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt); |
| 450 | 459 | ||
| 451 | dprintk("RPC: %s: closing\n", __func__); | 460 | dprintk("RPC: %s: closing\n", __func__); |
| 452 | xprt_disconnect(xprt); | 461 | xprt_disconnect_done(xprt); |
| 453 | (void) rpcrdma_ep_disconnect(&r_xprt->rx_ep, &r_xprt->rx_ia); | 462 | (void) rpcrdma_ep_disconnect(&r_xprt->rx_ep, &r_xprt->rx_ia); |
| 454 | } | 463 | } |
| 455 | 464 | ||
| @@ -682,7 +691,7 @@ xprt_rdma_send_request(struct rpc_task *task) | |||
| 682 | } | 691 | } |
| 683 | 692 | ||
| 684 | if (rpcrdma_ep_post(&r_xprt->rx_ia, &r_xprt->rx_ep, req)) { | 693 | if (rpcrdma_ep_post(&r_xprt->rx_ia, &r_xprt->rx_ep, req)) { |
| 685 | xprt_disconnect(xprt); | 694 | xprt_disconnect_done(xprt); |
| 686 | return -ENOTCONN; /* implies disconnect */ | 695 | return -ENOTCONN; /* implies disconnect */ |
| 687 | } | 696 | } |
| 688 | 697 | ||
diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 44b0fb942e8d..ffbf22a1d2ca 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c | |||
| @@ -522,7 +522,7 @@ rpcrdma_ep_create(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia, | |||
| 522 | struct rpcrdma_create_data_internal *cdata) | 522 | struct rpcrdma_create_data_internal *cdata) |
| 523 | { | 523 | { |
| 524 | struct ib_device_attr devattr; | 524 | struct ib_device_attr devattr; |
| 525 | int rc; | 525 | int rc, err; |
| 526 | 526 | ||
| 527 | rc = ib_query_device(ia->ri_id->device, &devattr); | 527 | rc = ib_query_device(ia->ri_id->device, &devattr); |
| 528 | if (rc) { | 528 | if (rc) { |
| @@ -648,8 +648,10 @@ rpcrdma_ep_create(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia, | |||
| 648 | return 0; | 648 | return 0; |
| 649 | 649 | ||
| 650 | out2: | 650 | out2: |
| 651 | if (ib_destroy_cq(ep->rep_cq)) | 651 | err = ib_destroy_cq(ep->rep_cq); |
| 652 | ; | 652 | if (err) |
| 653 | dprintk("RPC: %s: ib_destroy_cq returned %i\n", | ||
| 654 | __func__, err); | ||
| 653 | out1: | 655 | out1: |
| 654 | return rc; | 656 | return rc; |
| 655 | } | 657 | } |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 6fa52f44de0f..30e7ac243a90 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
| @@ -280,7 +280,9 @@ static inline struct sockaddr_in6 *xs_addr_in6(struct rpc_xprt *xprt) | |||
| 280 | return (struct sockaddr_in6 *) &xprt->addr; | 280 | return (struct sockaddr_in6 *) &xprt->addr; |
| 281 | } | 281 | } |
| 282 | 282 | ||
| 283 | static void xs_format_ipv4_peer_addresses(struct rpc_xprt *xprt) | 283 | static void xs_format_ipv4_peer_addresses(struct rpc_xprt *xprt, |
| 284 | const char *protocol, | ||
| 285 | const char *netid) | ||
| 284 | { | 286 | { |
| 285 | struct sockaddr_in *addr = xs_addr_in(xprt); | 287 | struct sockaddr_in *addr = xs_addr_in(xprt); |
| 286 | char *buf; | 288 | char *buf; |
| @@ -299,21 +301,14 @@ static void xs_format_ipv4_peer_addresses(struct rpc_xprt *xprt) | |||
| 299 | } | 301 | } |
| 300 | xprt->address_strings[RPC_DISPLAY_PORT] = buf; | 302 | xprt->address_strings[RPC_DISPLAY_PORT] = buf; |
| 301 | 303 | ||
| 302 | buf = kzalloc(8, GFP_KERNEL); | 304 | xprt->address_strings[RPC_DISPLAY_PROTO] = protocol; |
| 303 | if (buf) { | ||
| 304 | if (xprt->prot == IPPROTO_UDP) | ||
| 305 | snprintf(buf, 8, "udp"); | ||
| 306 | else | ||
| 307 | snprintf(buf, 8, "tcp"); | ||
| 308 | } | ||
| 309 | xprt->address_strings[RPC_DISPLAY_PROTO] = buf; | ||
| 310 | 305 | ||
| 311 | buf = kzalloc(48, GFP_KERNEL); | 306 | buf = kzalloc(48, GFP_KERNEL); |
| 312 | if (buf) { | 307 | if (buf) { |
| 313 | snprintf(buf, 48, "addr="NIPQUAD_FMT" port=%u proto=%s", | 308 | snprintf(buf, 48, "addr="NIPQUAD_FMT" port=%u proto=%s", |
| 314 | NIPQUAD(addr->sin_addr.s_addr), | 309 | NIPQUAD(addr->sin_addr.s_addr), |
| 315 | ntohs(addr->sin_port), | 310 | ntohs(addr->sin_port), |
| 316 | xprt->prot == IPPROTO_UDP ? "udp" : "tcp"); | 311 | protocol); |
| 317 | } | 312 | } |
| 318 | xprt->address_strings[RPC_DISPLAY_ALL] = buf; | 313 | xprt->address_strings[RPC_DISPLAY_ALL] = buf; |
| 319 | 314 | ||
| @@ -340,12 +335,12 @@ static void xs_format_ipv4_peer_addresses(struct rpc_xprt *xprt) | |||
| 340 | } | 335 | } |
| 341 | xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR] = buf; | 336 | xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR] = buf; |
| 342 | 337 | ||
| 343 | xprt->address_strings[RPC_DISPLAY_NETID] = | 338 | xprt->address_strings[RPC_DISPLAY_NETID] = netid; |
| 344 | kstrdup(xprt->prot == IPPROTO_UDP ? | ||
| 345 | RPCBIND_NETID_UDP : RPCBIND_NETID_TCP, GFP_KERNEL); | ||
| 346 | } | 339 | } |
| 347 | 340 | ||
| 348 | static void xs_format_ipv6_peer_addresses(struct rpc_xprt *xprt) | 341 | static void xs_format_ipv6_peer_addresses(struct rpc_xprt *xprt, |
| 342 | const char *protocol, | ||
| 343 | const char *netid) | ||
| 349 | { | 344 | { |
| 350 | struct sockaddr_in6 *addr = xs_addr_in6(xprt); | 345 | struct sockaddr_in6 *addr = xs_addr_in6(xprt); |
| 351 | char *buf; | 346 | char *buf; |
| @@ -364,21 +359,14 @@ static void xs_format_ipv6_peer_addresses(struct rpc_xprt *xprt) | |||
| 364 | } | 359 | } |
| 365 | xprt->address_strings[RPC_DISPLAY_PORT] = buf; | 360 | xprt->address_strings[RPC_DISPLAY_PORT] = buf; |
| 366 | 361 | ||
| 367 | buf = kzalloc(8, GFP_KERNEL); | 362 | xprt->address_strings[RPC_DISPLAY_PROTO] = protocol; |
| 368 | if (buf) { | ||
| 369 | if (xprt->prot == IPPROTO_UDP) | ||
| 370 | snprintf(buf, 8, "udp"); | ||
| 371 | else | ||
| 372 | snprintf(buf, 8, "tcp"); | ||
| 373 | } | ||
| 374 | xprt->address_strings[RPC_DISPLAY_PROTO] = buf; | ||
| 375 | 363 | ||
| 376 | buf = kzalloc(64, GFP_KERNEL); | 364 | buf = kzalloc(64, GFP_KERNEL); |
| 377 | if (buf) { | 365 | if (buf) { |
| 378 | snprintf(buf, 64, "addr="NIP6_FMT" port=%u proto=%s", | 366 | snprintf(buf, 64, "addr="NIP6_FMT" port=%u proto=%s", |
| 379 | NIP6(addr->sin6_addr), | 367 | NIP6(addr->sin6_addr), |
| 380 | ntohs(addr->sin6_port), | 368 | ntohs(addr->sin6_port), |
| 381 | xprt->prot == IPPROTO_UDP ? "udp" : "tcp"); | 369 | protocol); |
| 382 | } | 370 | } |
| 383 | xprt->address_strings[RPC_DISPLAY_ALL] = buf; | 371 | xprt->address_strings[RPC_DISPLAY_ALL] = buf; |
| 384 | 372 | ||
| @@ -405,17 +393,21 @@ static void xs_format_ipv6_peer_addresses(struct rpc_xprt *xprt) | |||
| 405 | } | 393 | } |
| 406 | xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR] = buf; | 394 | xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR] = buf; |
| 407 | 395 | ||
| 408 | xprt->address_strings[RPC_DISPLAY_NETID] = | 396 | xprt->address_strings[RPC_DISPLAY_NETID] = netid; |
| 409 | kstrdup(xprt->prot == IPPROTO_UDP ? | ||
| 410 | RPCBIND_NETID_UDP6 : RPCBIND_NETID_TCP6, GFP_KERNEL); | ||
| 411 | } | 397 | } |
| 412 | 398 | ||
| 413 | static void xs_free_peer_addresses(struct rpc_xprt *xprt) | 399 | static void xs_free_peer_addresses(struct rpc_xprt *xprt) |
| 414 | { | 400 | { |
| 415 | int i; | 401 | unsigned int i; |
| 416 | 402 | ||
| 417 | for (i = 0; i < RPC_DISPLAY_MAX; i++) | 403 | for (i = 0; i < RPC_DISPLAY_MAX; i++) |
| 418 | kfree(xprt->address_strings[i]); | 404 | switch (i) { |
| 405 | case RPC_DISPLAY_PROTO: | ||
| 406 | case RPC_DISPLAY_NETID: | ||
| 407 | continue; | ||
| 408 | default: | ||
| 409 | kfree(xprt->address_strings[i]); | ||
| 410 | } | ||
| 419 | } | 411 | } |
| 420 | 412 | ||
| 421 | #define XS_SENDMSG_FLAGS (MSG_DONTWAIT | MSG_NOSIGNAL) | 413 | #define XS_SENDMSG_FLAGS (MSG_DONTWAIT | MSG_NOSIGNAL) |
| @@ -614,6 +606,22 @@ static int xs_udp_send_request(struct rpc_task *task) | |||
| 614 | return status; | 606 | return status; |
| 615 | } | 607 | } |
| 616 | 608 | ||
| 609 | /** | ||
| 610 | * xs_tcp_shutdown - gracefully shut down a TCP socket | ||
| 611 | * @xprt: transport | ||
| 612 | * | ||
| 613 | * Initiates a graceful shutdown of the TCP socket by calling the | ||
| 614 | * equivalent of shutdown(SHUT_WR); | ||
| 615 | */ | ||
| 616 | static void xs_tcp_shutdown(struct rpc_xprt *xprt) | ||
| 617 | { | ||
| 618 | struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); | ||
| 619 | struct socket *sock = transport->sock; | ||
| 620 | |||
| 621 | if (sock != NULL) | ||
| 622 | kernel_sock_shutdown(sock, SHUT_WR); | ||
| 623 | } | ||
| 624 | |||
| 617 | static inline void xs_encode_tcp_record_marker(struct xdr_buf *buf) | 625 | static inline void xs_encode_tcp_record_marker(struct xdr_buf *buf) |
| 618 | { | 626 | { |
| 619 | u32 reclen = buf->len - sizeof(rpc_fraghdr); | 627 | u32 reclen = buf->len - sizeof(rpc_fraghdr); |
| @@ -691,7 +699,7 @@ static int xs_tcp_send_request(struct rpc_task *task) | |||
| 691 | default: | 699 | default: |
| 692 | dprintk("RPC: sendmsg returned unrecognized error %d\n", | 700 | dprintk("RPC: sendmsg returned unrecognized error %d\n", |
| 693 | -status); | 701 | -status); |
| 694 | xprt_disconnect(xprt); | 702 | xs_tcp_shutdown(xprt); |
| 695 | break; | 703 | break; |
| 696 | } | 704 | } |
| 697 | 705 | ||
| @@ -759,7 +767,9 @@ static void xs_close(struct rpc_xprt *xprt) | |||
| 759 | clear_close_wait: | 767 | clear_close_wait: |
| 760 | smp_mb__before_clear_bit(); | 768 | smp_mb__before_clear_bit(); |
| 761 | clear_bit(XPRT_CLOSE_WAIT, &xprt->state); | 769 | clear_bit(XPRT_CLOSE_WAIT, &xprt->state); |
| 770 | clear_bit(XPRT_CLOSING, &xprt->state); | ||
| 762 | smp_mb__after_clear_bit(); | 771 | smp_mb__after_clear_bit(); |
| 772 | xprt_disconnect_done(xprt); | ||
| 763 | } | 773 | } |
| 764 | 774 | ||
| 765 | /** | 775 | /** |
| @@ -775,7 +785,6 @@ static void xs_destroy(struct rpc_xprt *xprt) | |||
| 775 | 785 | ||
| 776 | cancel_rearming_delayed_work(&transport->connect_worker); | 786 | cancel_rearming_delayed_work(&transport->connect_worker); |
| 777 | 787 | ||
| 778 | xprt_disconnect(xprt); | ||
| 779 | xs_close(xprt); | 788 | xs_close(xprt); |
| 780 | xs_free_peer_addresses(xprt); | 789 | xs_free_peer_addresses(xprt); |
| 781 | kfree(xprt->slot); | 790 | kfree(xprt->slot); |
| @@ -886,7 +895,7 @@ static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, struct xdr_skb_rea | |||
| 886 | /* Sanity check of the record length */ | 895 | /* Sanity check of the record length */ |
| 887 | if (unlikely(transport->tcp_reclen < 4)) { | 896 | if (unlikely(transport->tcp_reclen < 4)) { |
| 888 | dprintk("RPC: invalid TCP record fragment length\n"); | 897 | dprintk("RPC: invalid TCP record fragment length\n"); |
| 889 | xprt_disconnect(xprt); | 898 | xprt_force_disconnect(xprt); |
| 890 | return; | 899 | return; |
| 891 | } | 900 | } |
| 892 | dprintk("RPC: reading TCP record fragment of length %d\n", | 901 | dprintk("RPC: reading TCP record fragment of length %d\n", |
| @@ -1113,21 +1122,44 @@ static void xs_tcp_state_change(struct sock *sk) | |||
| 1113 | transport->tcp_flags = | 1122 | transport->tcp_flags = |
| 1114 | TCP_RCV_COPY_FRAGHDR | TCP_RCV_COPY_XID; | 1123 | TCP_RCV_COPY_FRAGHDR | TCP_RCV_COPY_XID; |
| 1115 | 1124 | ||
| 1116 | xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO; | ||
| 1117 | xprt_wake_pending_tasks(xprt, 0); | 1125 | xprt_wake_pending_tasks(xprt, 0); |
| 1118 | } | 1126 | } |
| 1119 | spin_unlock_bh(&xprt->transport_lock); | 1127 | spin_unlock_bh(&xprt->transport_lock); |
| 1120 | break; | 1128 | break; |
| 1121 | case TCP_SYN_SENT: | 1129 | case TCP_FIN_WAIT1: |
| 1122 | case TCP_SYN_RECV: | 1130 | /* The client initiated a shutdown of the socket */ |
| 1131 | xprt->reestablish_timeout = 0; | ||
| 1132 | set_bit(XPRT_CLOSING, &xprt->state); | ||
| 1133 | smp_mb__before_clear_bit(); | ||
| 1134 | clear_bit(XPRT_CONNECTED, &xprt->state); | ||
| 1135 | clear_bit(XPRT_CLOSE_WAIT, &xprt->state); | ||
| 1136 | smp_mb__after_clear_bit(); | ||
| 1123 | break; | 1137 | break; |
| 1124 | case TCP_CLOSE_WAIT: | 1138 | case TCP_CLOSE_WAIT: |
| 1125 | /* Try to schedule an autoclose RPC calls */ | 1139 | /* The server initiated a shutdown of the socket */ |
| 1126 | set_bit(XPRT_CLOSE_WAIT, &xprt->state); | 1140 | set_bit(XPRT_CLOSING, &xprt->state); |
| 1127 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0) | 1141 | xprt_force_disconnect(xprt); |
| 1128 | queue_work(rpciod_workqueue, &xprt->task_cleanup); | 1142 | case TCP_SYN_SENT: |
| 1129 | default: | 1143 | case TCP_CLOSING: |
| 1130 | xprt_disconnect(xprt); | 1144 | /* |
| 1145 | * If the server closed down the connection, make sure that | ||
| 1146 | * we back off before reconnecting | ||
| 1147 | */ | ||
| 1148 | if (xprt->reestablish_timeout < XS_TCP_INIT_REEST_TO) | ||
| 1149 | xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO; | ||
| 1150 | break; | ||
| 1151 | case TCP_LAST_ACK: | ||
| 1152 | smp_mb__before_clear_bit(); | ||
| 1153 | clear_bit(XPRT_CONNECTED, &xprt->state); | ||
| 1154 | smp_mb__after_clear_bit(); | ||
| 1155 | break; | ||
| 1156 | case TCP_CLOSE: | ||
| 1157 | smp_mb__before_clear_bit(); | ||
| 1158 | clear_bit(XPRT_CLOSE_WAIT, &xprt->state); | ||
| 1159 | clear_bit(XPRT_CLOSING, &xprt->state); | ||
| 1160 | smp_mb__after_clear_bit(); | ||
| 1161 | /* Mark transport as closed and wake up all pending tasks */ | ||
| 1162 | xprt_disconnect_done(xprt); | ||
| 1131 | } | 1163 | } |
| 1132 | out: | 1164 | out: |
| 1133 | read_unlock(&sk->sk_callback_lock); | 1165 | read_unlock(&sk->sk_callback_lock); |
| @@ -1279,34 +1311,53 @@ static void xs_set_port(struct rpc_xprt *xprt, unsigned short port) | |||
| 1279 | } | 1311 | } |
| 1280 | } | 1312 | } |
| 1281 | 1313 | ||
| 1314 | static unsigned short xs_get_srcport(struct sock_xprt *transport, struct socket *sock) | ||
| 1315 | { | ||
| 1316 | unsigned short port = transport->port; | ||
| 1317 | |||
| 1318 | if (port == 0 && transport->xprt.resvport) | ||
| 1319 | port = xs_get_random_port(); | ||
| 1320 | return port; | ||
| 1321 | } | ||
| 1322 | |||
| 1323 | static unsigned short xs_next_srcport(struct sock_xprt *transport, struct socket *sock, unsigned short port) | ||
| 1324 | { | ||
| 1325 | if (transport->port != 0) | ||
| 1326 | transport->port = 0; | ||
| 1327 | if (!transport->xprt.resvport) | ||
| 1328 | return 0; | ||
| 1329 | if (port <= xprt_min_resvport || port > xprt_max_resvport) | ||
| 1330 | return xprt_max_resvport; | ||
| 1331 | return --port; | ||
| 1332 | } | ||
| 1333 | |||
| 1282 | static int xs_bind4(struct sock_xprt *transport, struct socket *sock) | 1334 | static int xs_bind4(struct sock_xprt *transport, struct socket *sock) |
| 1283 | { | 1335 | { |
| 1284 | struct sockaddr_in myaddr = { | 1336 | struct sockaddr_in myaddr = { |
| 1285 | .sin_family = AF_INET, | 1337 | .sin_family = AF_INET, |
| 1286 | }; | 1338 | }; |
| 1287 | struct sockaddr_in *sa; | 1339 | struct sockaddr_in *sa; |
| 1288 | int err; | 1340 | int err, nloop = 0; |
| 1289 | unsigned short port = transport->port; | 1341 | unsigned short port = xs_get_srcport(transport, sock); |
| 1342 | unsigned short last; | ||
| 1290 | 1343 | ||
| 1291 | if (!transport->xprt.resvport) | ||
| 1292 | port = 0; | ||
| 1293 | sa = (struct sockaddr_in *)&transport->addr; | 1344 | sa = (struct sockaddr_in *)&transport->addr; |
| 1294 | myaddr.sin_addr = sa->sin_addr; | 1345 | myaddr.sin_addr = sa->sin_addr; |
| 1295 | do { | 1346 | do { |
| 1296 | myaddr.sin_port = htons(port); | 1347 | myaddr.sin_port = htons(port); |
| 1297 | err = kernel_bind(sock, (struct sockaddr *) &myaddr, | 1348 | err = kernel_bind(sock, (struct sockaddr *) &myaddr, |
| 1298 | sizeof(myaddr)); | 1349 | sizeof(myaddr)); |
| 1299 | if (!transport->xprt.resvport) | 1350 | if (port == 0) |
| 1300 | break; | 1351 | break; |
| 1301 | if (err == 0) { | 1352 | if (err == 0) { |
| 1302 | transport->port = port; | 1353 | transport->port = port; |
| 1303 | break; | 1354 | break; |
| 1304 | } | 1355 | } |
| 1305 | if (port <= xprt_min_resvport) | 1356 | last = port; |
| 1306 | port = xprt_max_resvport; | 1357 | port = xs_next_srcport(transport, sock, port); |
| 1307 | else | 1358 | if (port > last) |
| 1308 | port--; | 1359 | nloop++; |
| 1309 | } while (err == -EADDRINUSE && port != transport->port); | 1360 | } while (err == -EADDRINUSE && nloop != 2); |
| 1310 | dprintk("RPC: %s "NIPQUAD_FMT":%u: %s (%d)\n", | 1361 | dprintk("RPC: %s "NIPQUAD_FMT":%u: %s (%d)\n", |
| 1311 | __FUNCTION__, NIPQUAD(myaddr.sin_addr), | 1362 | __FUNCTION__, NIPQUAD(myaddr.sin_addr), |
| 1312 | port, err ? "failed" : "ok", err); | 1363 | port, err ? "failed" : "ok", err); |
| @@ -1319,28 +1370,27 @@ static int xs_bind6(struct sock_xprt *transport, struct socket *sock) | |||
| 1319 | .sin6_family = AF_INET6, | 1370 | .sin6_family = AF_INET6, |
| 1320 | }; | 1371 | }; |
| 1321 | struct sockaddr_in6 *sa; | 1372 | struct sockaddr_in6 *sa; |
| 1322 | int err; | 1373 | int err, nloop = 0; |
| 1323 | unsigned short port = transport->port; | 1374 | unsigned short port = xs_get_srcport(transport, sock); |
| 1375 | unsigned short last; | ||
| 1324 | 1376 | ||
| 1325 | if (!transport->xprt.resvport) | ||
| 1326 | port = 0; | ||
| 1327 | sa = (struct sockaddr_in6 *)&transport->addr; | 1377 | sa = (struct sockaddr_in6 *)&transport->addr; |
| 1328 | myaddr.sin6_addr = sa->sin6_addr; | 1378 | myaddr.sin6_addr = sa->sin6_addr; |
| 1329 | do { | 1379 | do { |
| 1330 | myaddr.sin6_port = htons(port); | 1380 | myaddr.sin6_port = htons(port); |
| 1331 | err = kernel_bind(sock, (struct sockaddr *) &myaddr, | 1381 | err = kernel_bind(sock, (struct sockaddr *) &myaddr, |
| 1332 | sizeof(myaddr)); | 1382 | sizeof(myaddr)); |
| 1333 | if (!transport->xprt.resvport) | 1383 | if (port == 0) |
| 1334 | break; | 1384 | break; |
| 1335 | if (err == 0) { | 1385 | if (err == 0) { |
| 1336 | transport->port = port; | 1386 | transport->port = port; |
| 1337 | break; | 1387 | break; |
| 1338 | } | 1388 | } |
| 1339 | if (port <= xprt_min_resvport) | 1389 | last = port; |
| 1340 | port = xprt_max_resvport; | 1390 | port = xs_next_srcport(transport, sock, port); |
| 1341 | else | 1391 | if (port > last) |
| 1342 | port--; | 1392 | nloop++; |
| 1343 | } while (err == -EADDRINUSE && port != transport->port); | 1393 | } while (err == -EADDRINUSE && nloop != 2); |
| 1344 | dprintk("RPC: xs_bind6 "NIP6_FMT":%u: %s (%d)\n", | 1394 | dprintk("RPC: xs_bind6 "NIP6_FMT":%u: %s (%d)\n", |
| 1345 | NIP6(myaddr.sin6_addr), port, err ? "failed" : "ok", err); | 1395 | NIP6(myaddr.sin6_addr), port, err ? "failed" : "ok", err); |
| 1346 | return err; | 1396 | return err; |
| @@ -1602,8 +1652,7 @@ static void xs_tcp_connect_worker4(struct work_struct *work) | |||
| 1602 | break; | 1652 | break; |
| 1603 | default: | 1653 | default: |
| 1604 | /* get rid of existing socket, and retry */ | 1654 | /* get rid of existing socket, and retry */ |
| 1605 | xs_close(xprt); | 1655 | xs_tcp_shutdown(xprt); |
| 1606 | break; | ||
| 1607 | } | 1656 | } |
| 1608 | } | 1657 | } |
| 1609 | out: | 1658 | out: |
| @@ -1662,8 +1711,7 @@ static void xs_tcp_connect_worker6(struct work_struct *work) | |||
| 1662 | break; | 1711 | break; |
| 1663 | default: | 1712 | default: |
| 1664 | /* get rid of existing socket, and retry */ | 1713 | /* get rid of existing socket, and retry */ |
| 1665 | xs_close(xprt); | 1714 | xs_tcp_shutdown(xprt); |
| 1666 | break; | ||
| 1667 | } | 1715 | } |
| 1668 | } | 1716 | } |
| 1669 | out: | 1717 | out: |
| @@ -1710,6 +1758,19 @@ static void xs_connect(struct rpc_task *task) | |||
| 1710 | } | 1758 | } |
| 1711 | } | 1759 | } |
| 1712 | 1760 | ||
| 1761 | static void xs_tcp_connect(struct rpc_task *task) | ||
| 1762 | { | ||
| 1763 | struct rpc_xprt *xprt = task->tk_xprt; | ||
| 1764 | |||
| 1765 | /* Initiate graceful shutdown of the socket if not already done */ | ||
| 1766 | if (test_bit(XPRT_CONNECTED, &xprt->state)) | ||
| 1767 | xs_tcp_shutdown(xprt); | ||
| 1768 | /* Exit if we need to wait for socket shutdown to complete */ | ||
| 1769 | if (test_bit(XPRT_CLOSING, &xprt->state)) | ||
| 1770 | return; | ||
| 1771 | xs_connect(task); | ||
| 1772 | } | ||
| 1773 | |||
| 1713 | /** | 1774 | /** |
| 1714 | * xs_udp_print_stats - display UDP socket-specifc stats | 1775 | * xs_udp_print_stats - display UDP socket-specifc stats |
| 1715 | * @xprt: rpc_xprt struct containing statistics | 1776 | * @xprt: rpc_xprt struct containing statistics |
| @@ -1780,12 +1841,12 @@ static struct rpc_xprt_ops xs_tcp_ops = { | |||
| 1780 | .release_xprt = xs_tcp_release_xprt, | 1841 | .release_xprt = xs_tcp_release_xprt, |
| 1781 | .rpcbind = rpcb_getport_async, | 1842 | .rpcbind = rpcb_getport_async, |
| 1782 | .set_port = xs_set_port, | 1843 | .set_port = xs_set_port, |
| 1783 | .connect = xs_connect, | 1844 | .connect = xs_tcp_connect, |
| 1784 | .buf_alloc = rpc_malloc, | 1845 | .buf_alloc = rpc_malloc, |
| 1785 | .buf_free = rpc_free, | 1846 | .buf_free = rpc_free, |
| 1786 | .send_request = xs_tcp_send_request, | 1847 | .send_request = xs_tcp_send_request, |
| 1787 | .set_retrans_timeout = xprt_set_retrans_timeout_def, | 1848 | .set_retrans_timeout = xprt_set_retrans_timeout_def, |
| 1788 | .close = xs_close, | 1849 | .close = xs_tcp_shutdown, |
| 1789 | .destroy = xs_destroy, | 1850 | .destroy = xs_destroy, |
| 1790 | .print_stats = xs_tcp_print_stats, | 1851 | .print_stats = xs_tcp_print_stats, |
| 1791 | }; | 1852 | }; |
| @@ -1822,11 +1883,17 @@ static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args, | |||
| 1822 | xprt->addrlen = args->addrlen; | 1883 | xprt->addrlen = args->addrlen; |
| 1823 | if (args->srcaddr) | 1884 | if (args->srcaddr) |
| 1824 | memcpy(&new->addr, args->srcaddr, args->addrlen); | 1885 | memcpy(&new->addr, args->srcaddr, args->addrlen); |
| 1825 | new->port = xs_get_random_port(); | ||
| 1826 | 1886 | ||
| 1827 | return xprt; | 1887 | return xprt; |
| 1828 | } | 1888 | } |
| 1829 | 1889 | ||
| 1890 | static const struct rpc_timeout xs_udp_default_timeout = { | ||
| 1891 | .to_initval = 5 * HZ, | ||
| 1892 | .to_maxval = 30 * HZ, | ||
| 1893 | .to_increment = 5 * HZ, | ||
| 1894 | .to_retries = 5, | ||
| 1895 | }; | ||
| 1896 | |||
| 1830 | /** | 1897 | /** |
| 1831 | * xs_setup_udp - Set up transport to use a UDP socket | 1898 | * xs_setup_udp - Set up transport to use a UDP socket |
| 1832 | * @args: rpc transport creation arguments | 1899 | * @args: rpc transport creation arguments |
| @@ -1855,10 +1922,7 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args) | |||
| 1855 | 1922 | ||
| 1856 | xprt->ops = &xs_udp_ops; | 1923 | xprt->ops = &xs_udp_ops; |
| 1857 | 1924 | ||
| 1858 | if (args->timeout) | 1925 | xprt->timeout = &xs_udp_default_timeout; |
| 1859 | xprt->timeout = *args->timeout; | ||
| 1860 | else | ||
| 1861 | xprt_set_timeout(&xprt->timeout, 5, 5 * HZ); | ||
| 1862 | 1926 | ||
| 1863 | switch (addr->sa_family) { | 1927 | switch (addr->sa_family) { |
| 1864 | case AF_INET: | 1928 | case AF_INET: |
| @@ -1867,7 +1931,7 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args) | |||
| 1867 | 1931 | ||
| 1868 | INIT_DELAYED_WORK(&transport->connect_worker, | 1932 | INIT_DELAYED_WORK(&transport->connect_worker, |
| 1869 | xs_udp_connect_worker4); | 1933 | xs_udp_connect_worker4); |
| 1870 | xs_format_ipv4_peer_addresses(xprt); | 1934 | xs_format_ipv4_peer_addresses(xprt, "udp", RPCBIND_NETID_UDP); |
| 1871 | break; | 1935 | break; |
| 1872 | case AF_INET6: | 1936 | case AF_INET6: |
| 1873 | if (((struct sockaddr_in6 *)addr)->sin6_port != htons(0)) | 1937 | if (((struct sockaddr_in6 *)addr)->sin6_port != htons(0)) |
| @@ -1875,7 +1939,7 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args) | |||
| 1875 | 1939 | ||
| 1876 | INIT_DELAYED_WORK(&transport->connect_worker, | 1940 | INIT_DELAYED_WORK(&transport->connect_worker, |
| 1877 | xs_udp_connect_worker6); | 1941 | xs_udp_connect_worker6); |
| 1878 | xs_format_ipv6_peer_addresses(xprt); | 1942 | xs_format_ipv6_peer_addresses(xprt, "udp", RPCBIND_NETID_UDP6); |
| 1879 | break; | 1943 | break; |
| 1880 | default: | 1944 | default: |
| 1881 | kfree(xprt); | 1945 | kfree(xprt); |
| @@ -1893,6 +1957,12 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args) | |||
| 1893 | return ERR_PTR(-EINVAL); | 1957 | return ERR_PTR(-EINVAL); |
| 1894 | } | 1958 | } |
| 1895 | 1959 | ||
| 1960 | static const struct rpc_timeout xs_tcp_default_timeout = { | ||
| 1961 | .to_initval = 60 * HZ, | ||
| 1962 | .to_maxval = 60 * HZ, | ||
| 1963 | .to_retries = 2, | ||
| 1964 | }; | ||
| 1965 | |||
| 1896 | /** | 1966 | /** |
| 1897 | * xs_setup_tcp - Set up transport to use a TCP socket | 1967 | * xs_setup_tcp - Set up transport to use a TCP socket |
| 1898 | * @args: rpc transport creation arguments | 1968 | * @args: rpc transport creation arguments |
| @@ -1919,11 +1989,7 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args) | |||
| 1919 | xprt->idle_timeout = XS_IDLE_DISC_TO; | 1989 | xprt->idle_timeout = XS_IDLE_DISC_TO; |
| 1920 | 1990 | ||
| 1921 | xprt->ops = &xs_tcp_ops; | 1991 | xprt->ops = &xs_tcp_ops; |
| 1922 | 1992 | xprt->timeout = &xs_tcp_default_timeout; | |
| 1923 | if (args->timeout) | ||
| 1924 | xprt->timeout = *args->timeout; | ||
| 1925 | else | ||
| 1926 | xprt_set_timeout(&xprt->timeout, 2, 60 * HZ); | ||
| 1927 | 1993 | ||
| 1928 | switch (addr->sa_family) { | 1994 | switch (addr->sa_family) { |
| 1929 | case AF_INET: | 1995 | case AF_INET: |
| @@ -1931,14 +1997,14 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args) | |||
| 1931 | xprt_set_bound(xprt); | 1997 | xprt_set_bound(xprt); |
| 1932 | 1998 | ||
| 1933 | INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_connect_worker4); | 1999 | INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_connect_worker4); |
| 1934 | xs_format_ipv4_peer_addresses(xprt); | 2000 | xs_format_ipv4_peer_addresses(xprt, "tcp", RPCBIND_NETID_TCP); |
| 1935 | break; | 2001 | break; |
| 1936 | case AF_INET6: | 2002 | case AF_INET6: |
| 1937 | if (((struct sockaddr_in6 *)addr)->sin6_port != htons(0)) | 2003 | if (((struct sockaddr_in6 *)addr)->sin6_port != htons(0)) |
| 1938 | xprt_set_bound(xprt); | 2004 | xprt_set_bound(xprt); |
| 1939 | 2005 | ||
| 1940 | INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_connect_worker6); | 2006 | INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_connect_worker6); |
| 1941 | xs_format_ipv6_peer_addresses(xprt); | 2007 | xs_format_ipv6_peer_addresses(xprt, "tcp", RPCBIND_NETID_TCP6); |
| 1942 | break; | 2008 | break; |
| 1943 | default: | 2009 | default: |
| 1944 | kfree(xprt); | 2010 | kfree(xprt); |
