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 /fs | |
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
...
Diffstat (limited to 'fs')
-rw-r--r-- | fs/lockd/clntlock.c | 42 | ||||
-rw-r--r-- | fs/lockd/clntproc.c | 35 | ||||
-rw-r--r-- | fs/lockd/xdr.c | 3 | ||||
-rw-r--r-- | fs/nfs/callback.c | 7 | ||||
-rw-r--r-- | fs/nfs/callback.h | 4 | ||||
-rw-r--r-- | fs/nfs/callback_proc.c | 51 | ||||
-rw-r--r-- | fs/nfs/callback_xdr.c | 6 | ||||
-rw-r--r-- | fs/nfs/client.c | 352 | ||||
-rw-r--r-- | fs/nfs/delegation.c | 110 | ||||
-rw-r--r-- | fs/nfs/delegation.h | 3 | ||||
-rw-r--r-- | fs/nfs/dir.c | 63 | ||||
-rw-r--r-- | fs/nfs/direct.c | 124 | ||||
-rw-r--r-- | fs/nfs/file.c | 40 | ||||
-rw-r--r-- | fs/nfs/idmap.c | 99 | ||||
-rw-r--r-- | fs/nfs/inode.c | 34 | ||||
-rw-r--r-- | fs/nfs/internal.h | 16 | ||||
-rw-r--r-- | fs/nfs/namespace.c | 2 | ||||
-rw-r--r-- | fs/nfs/nfs2xdr.c | 24 | ||||
-rw-r--r-- | fs/nfs/nfs3proc.c | 45 | ||||
-rw-r--r-- | fs/nfs/nfs3xdr.c | 27 | ||||
-rw-r--r-- | fs/nfs/nfs4namespace.c | 20 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 288 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 41 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 40 | ||||
-rw-r--r-- | fs/nfs/pagelist.c | 13 | ||||
-rw-r--r-- | fs/nfs/proc.c | 30 | ||||
-rw-r--r-- | fs/nfs/read.c | 50 | ||||
-rw-r--r-- | fs/nfs/super.c | 297 | ||||
-rw-r--r-- | fs/nfs/unlink.c | 45 | ||||
-rw-r--r-- | fs/nfs/write.c | 107 |
30 files changed, 1216 insertions, 802 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)) { |