diff options
| author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2008-12-30 16:51:43 -0500 |
|---|---|---|
| committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2008-12-30 16:51:43 -0500 |
| commit | 08cc36cbd1ee7d86422713bb21551eed1326b894 (patch) | |
| tree | 52cc683387f903b34a7f6f798dcdbae385b58db8 | |
| parent | 3c92ec8ae91ecf59d88c798301833d7cf83f2179 (diff) | |
| parent | 46f72f57d279688c4524df78edb5738db730eeef (diff) | |
Merge branch 'devel' into next
43 files changed, 1876 insertions, 1442 deletions
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index 8307dd64bf46..1f3b0fc0d351 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include <linux/sunrpc/svc.h> | 14 | #include <linux/sunrpc/svc.h> |
| 15 | #include <linux/lockd/lockd.h> | 15 | #include <linux/lockd/lockd.h> |
| 16 | #include <linux/smp_lock.h> | 16 | #include <linux/smp_lock.h> |
| 17 | #include <linux/kthread.h> | ||
| 17 | 18 | ||
| 18 | #define NLMDBG_FACILITY NLMDBG_CLIENT | 19 | #define NLMDBG_FACILITY NLMDBG_CLIENT |
| 19 | 20 | ||
| @@ -60,7 +61,7 @@ struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init) | |||
| 60 | 61 | ||
| 61 | host = nlmclnt_lookup_host(nlm_init->address, nlm_init->addrlen, | 62 | host = nlmclnt_lookup_host(nlm_init->address, nlm_init->addrlen, |
| 62 | nlm_init->protocol, nlm_version, | 63 | nlm_init->protocol, nlm_version, |
| 63 | nlm_init->hostname); | 64 | nlm_init->hostname, nlm_init->noresvport); |
| 64 | if (host == NULL) { | 65 | if (host == NULL) { |
| 65 | lockd_down(); | 66 | lockd_down(); |
| 66 | return ERR_PTR(-ENOLCK); | 67 | return ERR_PTR(-ENOLCK); |
| @@ -191,11 +192,15 @@ __be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock) | |||
| 191 | void | 192 | void |
| 192 | nlmclnt_recovery(struct nlm_host *host) | 193 | nlmclnt_recovery(struct nlm_host *host) |
| 193 | { | 194 | { |
| 195 | struct task_struct *task; | ||
| 196 | |||
| 194 | if (!host->h_reclaiming++) { | 197 | if (!host->h_reclaiming++) { |
| 195 | nlm_get_host(host); | 198 | nlm_get_host(host); |
| 196 | __module_get(THIS_MODULE); | 199 | task = kthread_run(reclaimer, host, "%s-reclaim", host->h_name); |
| 197 | if (kernel_thread(reclaimer, host, CLONE_FS | CLONE_FILES) < 0) | 200 | if (IS_ERR(task)) |
| 198 | module_put(THIS_MODULE); | 201 | printk(KERN_ERR "lockd: unable to spawn reclaimer " |
| 202 | "thread. Locks for %s won't be reclaimed! " | ||
| 203 | "(%ld)\n", host->h_name, PTR_ERR(task)); | ||
| 199 | } | 204 | } |
| 200 | } | 205 | } |
| 201 | 206 | ||
| @@ -207,7 +212,6 @@ reclaimer(void *ptr) | |||
| 207 | struct file_lock *fl, *next; | 212 | struct file_lock *fl, *next; |
| 208 | u32 nsmstate; | 213 | u32 nsmstate; |
| 209 | 214 | ||
| 210 | daemonize("%s-reclaim", host->h_name); | ||
| 211 | allow_signal(SIGKILL); | 215 | allow_signal(SIGKILL); |
| 212 | 216 | ||
| 213 | down_write(&host->h_rwsem); | 217 | down_write(&host->h_rwsem); |
| @@ -233,7 +237,12 @@ restart: | |||
| 233 | list_for_each_entry_safe(fl, next, &host->h_reclaim, fl_u.nfs_fl.list) { | 237 | list_for_each_entry_safe(fl, next, &host->h_reclaim, fl_u.nfs_fl.list) { |
| 234 | list_del_init(&fl->fl_u.nfs_fl.list); | 238 | list_del_init(&fl->fl_u.nfs_fl.list); |
| 235 | 239 | ||
| 236 | /* Why are we leaking memory here? --okir */ | 240 | /* |
| 241 | * sending this thread a SIGKILL will result in any unreclaimed | ||
| 242 | * locks being removed from the h_granted list. This means that | ||
| 243 | * the kernel will not attempt to reclaim them again if a new | ||
| 244 | * reclaimer thread is spawned for this host. | ||
| 245 | */ | ||
| 237 | if (signalled()) | 246 | if (signalled()) |
| 238 | continue; | 247 | continue; |
| 239 | if (nlmclnt_reclaim(host, fl) != 0) | 248 | if (nlmclnt_reclaim(host, fl) != 0) |
| @@ -261,5 +270,5 @@ restart: | |||
| 261 | nlm_release_host(host); | 270 | nlm_release_host(host); |
| 262 | lockd_down(); | 271 | lockd_down(); |
| 263 | unlock_kernel(); | 272 | unlock_kernel(); |
| 264 | module_put_and_exit(0); | 273 | return 0; |
| 265 | } | 274 | } |
diff --git a/fs/lockd/host.c b/fs/lockd/host.c index e05d04416037..abdebf76b820 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c | |||
| @@ -48,6 +48,7 @@ struct nlm_lookup_host_info { | |||
| 48 | const size_t hostname_len; /* it's length */ | 48 | const size_t hostname_len; /* it's length */ |
| 49 | const struct sockaddr *src_sap; /* our address (optional) */ | 49 | const struct sockaddr *src_sap; /* our address (optional) */ |
| 50 | const size_t src_len; /* it's length */ | 50 | const size_t src_len; /* it's length */ |
| 51 | const int noresvport; /* use non-priv port */ | ||
| 51 | }; | 52 | }; |
| 52 | 53 | ||
| 53 | /* | 54 | /* |
| @@ -222,6 +223,7 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni) | |||
| 222 | host->h_nsmstate = 0; /* real NSM state */ | 223 | host->h_nsmstate = 0; /* real NSM state */ |
| 223 | host->h_nsmhandle = nsm; | 224 | host->h_nsmhandle = nsm; |
| 224 | host->h_server = ni->server; | 225 | host->h_server = ni->server; |
| 226 | host->h_noresvport = ni->noresvport; | ||
| 225 | hlist_add_head(&host->h_hash, chain); | 227 | hlist_add_head(&host->h_hash, chain); |
| 226 | INIT_LIST_HEAD(&host->h_lockowners); | 228 | INIT_LIST_HEAD(&host->h_lockowners); |
| 227 | spin_lock_init(&host->h_lock); | 229 | spin_lock_init(&host->h_lock); |
| @@ -272,6 +274,7 @@ nlm_destroy_host(struct nlm_host *host) | |||
| 272 | * @protocol: transport protocol to use | 274 | * @protocol: transport protocol to use |
| 273 | * @version: NLM protocol version | 275 | * @version: NLM protocol version |
| 274 | * @hostname: '\0'-terminated hostname of server | 276 | * @hostname: '\0'-terminated hostname of server |
| 277 | * @noresvport: 1 if non-privileged port should be used | ||
| 275 | * | 278 | * |
| 276 | * Returns an nlm_host structure that matches the passed-in | 279 | * Returns an nlm_host structure that matches the passed-in |
| 277 | * [server address, transport protocol, NLM version, server hostname]. | 280 | * [server address, transport protocol, NLM version, server hostname]. |
| @@ -281,7 +284,9 @@ nlm_destroy_host(struct nlm_host *host) | |||
| 281 | struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap, | 284 | struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap, |
| 282 | const size_t salen, | 285 | const size_t salen, |
| 283 | const unsigned short protocol, | 286 | const unsigned short protocol, |
| 284 | const u32 version, const char *hostname) | 287 | const u32 version, |
| 288 | const char *hostname, | ||
| 289 | int noresvport) | ||
| 285 | { | 290 | { |
| 286 | const struct sockaddr source = { | 291 | const struct sockaddr source = { |
| 287 | .sa_family = AF_UNSPEC, | 292 | .sa_family = AF_UNSPEC, |
| @@ -296,6 +301,7 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap, | |||
| 296 | .hostname_len = strlen(hostname), | 301 | .hostname_len = strlen(hostname), |
| 297 | .src_sap = &source, | 302 | .src_sap = &source, |
| 298 | .src_len = sizeof(source), | 303 | .src_len = sizeof(source), |
| 304 | .noresvport = noresvport, | ||
| 299 | }; | 305 | }; |
| 300 | 306 | ||
| 301 | dprintk("lockd: %s(host='%s', vers=%u, proto=%s)\n", __func__, | 307 | dprintk("lockd: %s(host='%s', vers=%u, proto=%s)\n", __func__, |
| @@ -417,6 +423,8 @@ nlm_bind_host(struct nlm_host *host) | |||
| 417 | */ | 423 | */ |
| 418 | if (!host->h_server) | 424 | if (!host->h_server) |
| 419 | args.flags |= RPC_CLNT_CREATE_HARDRTRY; | 425 | args.flags |= RPC_CLNT_CREATE_HARDRTRY; |
| 426 | if (host->h_noresvport) | ||
| 427 | args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; | ||
| 420 | 428 | ||
| 421 | clnt = rpc_create(&args); | 429 | clnt = rpc_create(&args); |
| 422 | if (!IS_ERR(clnt)) | 430 | if (!IS_ERR(clnt)) |
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 56b076736b56..252d80163d02 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c | |||
| @@ -45,7 +45,7 @@ | |||
| 45 | static struct svc_program nlmsvc_program; | 45 | static struct svc_program nlmsvc_program; |
| 46 | 46 | ||
| 47 | struct nlmsvc_binding * nlmsvc_ops; | 47 | struct nlmsvc_binding * nlmsvc_ops; |
| 48 | EXPORT_SYMBOL(nlmsvc_ops); | 48 | EXPORT_SYMBOL_GPL(nlmsvc_ops); |
| 49 | 49 | ||
| 50 | static DEFINE_MUTEX(nlmsvc_mutex); | 50 | static DEFINE_MUTEX(nlmsvc_mutex); |
| 51 | static unsigned int nlmsvc_users; | 51 | static unsigned int nlmsvc_users; |
| @@ -300,7 +300,7 @@ out: | |||
| 300 | mutex_unlock(&nlmsvc_mutex); | 300 | mutex_unlock(&nlmsvc_mutex); |
| 301 | return error; | 301 | return error; |
| 302 | } | 302 | } |
| 303 | EXPORT_SYMBOL(lockd_up); | 303 | EXPORT_SYMBOL_GPL(lockd_up); |
| 304 | 304 | ||
| 305 | /* | 305 | /* |
| 306 | * Decrement the user count and bring down lockd if we're the last. | 306 | * Decrement the user count and bring down lockd if we're the last. |
| @@ -329,7 +329,7 @@ lockd_down(void) | |||
| 329 | out: | 329 | out: |
| 330 | mutex_unlock(&nlmsvc_mutex); | 330 | mutex_unlock(&nlmsvc_mutex); |
| 331 | } | 331 | } |
| 332 | EXPORT_SYMBOL(lockd_down); | 332 | EXPORT_SYMBOL_GPL(lockd_down); |
| 333 | 333 | ||
| 334 | #ifdef CONFIG_SYSCTL | 334 | #ifdef CONFIG_SYSCTL |
| 335 | 335 | ||
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index c2e9cfd9e5a4..3e634f2a1083 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/mutex.h> | 16 | #include <linux/mutex.h> |
| 17 | #include <linux/freezer.h> | 17 | #include <linux/freezer.h> |
| 18 | #include <linux/kthread.h> | 18 | #include <linux/kthread.h> |
| 19 | #include <linux/sunrpc/svcauth_gss.h> | ||
| 19 | 20 | ||
| 20 | #include <net/inet_sock.h> | 21 | #include <net/inet_sock.h> |
| 21 | 22 | ||
| @@ -182,10 +183,34 @@ void nfs_callback_down(void) | |||
| 182 | mutex_unlock(&nfs_callback_mutex); | 183 | mutex_unlock(&nfs_callback_mutex); |
| 183 | } | 184 | } |
| 184 | 185 | ||
| 186 | static int check_gss_callback_principal(struct nfs_client *clp, | ||
| 187 | struct svc_rqst *rqstp) | ||
| 188 | { | ||
| 189 | struct rpc_clnt *r = clp->cl_rpcclient; | ||
| 190 | char *p = svc_gss_principal(rqstp); | ||
| 191 | |||
| 192 | /* | ||
| 193 | * It might just be a normal user principal, in which case | ||
| 194 | * userspace won't bother to tell us the name at all. | ||
| 195 | */ | ||
| 196 | if (p == NULL) | ||
| 197 | return SVC_DENIED; | ||
| 198 | |||
| 199 | /* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */ | ||
| 200 | |||
| 201 | if (memcmp(p, "nfs@", 4) != 0) | ||
| 202 | return SVC_DENIED; | ||
| 203 | p += 4; | ||
| 204 | if (strcmp(p, r->cl_server) != 0) | ||
| 205 | return SVC_DENIED; | ||
| 206 | return SVC_OK; | ||
| 207 | } | ||
| 208 | |||
| 185 | static int nfs_callback_authenticate(struct svc_rqst *rqstp) | 209 | static int nfs_callback_authenticate(struct svc_rqst *rqstp) |
| 186 | { | 210 | { |
| 187 | struct nfs_client *clp; | 211 | struct nfs_client *clp; |
| 188 | RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); | 212 | RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); |
| 213 | int ret = SVC_OK; | ||
| 189 | 214 | ||
| 190 | /* Don't talk to strangers */ | 215 | /* Don't talk to strangers */ |
| 191 | clp = nfs_find_client(svc_addr(rqstp), 4); | 216 | clp = nfs_find_client(svc_addr(rqstp), 4); |
| @@ -194,21 +219,22 @@ static int nfs_callback_authenticate(struct svc_rqst *rqstp) | |||
| 194 | 219 | ||
| 195 | dprintk("%s: %s NFSv4 callback!\n", __func__, | 220 | dprintk("%s: %s NFSv4 callback!\n", __func__, |
| 196 | svc_print_addr(rqstp, buf, sizeof(buf))); | 221 | svc_print_addr(rqstp, buf, sizeof(buf))); |
| 197 | nfs_put_client(clp); | ||
| 198 | 222 | ||
| 199 | switch (rqstp->rq_authop->flavour) { | 223 | switch (rqstp->rq_authop->flavour) { |
| 200 | case RPC_AUTH_NULL: | 224 | case RPC_AUTH_NULL: |
| 201 | if (rqstp->rq_proc != CB_NULL) | 225 | if (rqstp->rq_proc != CB_NULL) |
| 202 | return SVC_DENIED; | 226 | ret = SVC_DENIED; |
| 203 | break; | 227 | break; |
| 204 | case RPC_AUTH_UNIX: | 228 | case RPC_AUTH_UNIX: |
| 205 | break; | 229 | break; |
| 206 | case RPC_AUTH_GSS: | 230 | case RPC_AUTH_GSS: |
| 207 | /* FIXME: RPCSEC_GSS handling? */ | 231 | ret = check_gss_callback_principal(clp, rqstp); |
| 232 | break; | ||
| 208 | default: | 233 | default: |
| 209 | return SVC_DENIED; | 234 | ret = SVC_DENIED; |
| 210 | } | 235 | } |
| 211 | return SVC_OK; | 236 | nfs_put_client(clp); |
| 237 | return ret; | ||
| 212 | } | 238 | } |
| 213 | 239 | ||
| 214 | /* | 240 | /* |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 7547600b6174..9b728f3565a1 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
| @@ -143,7 +143,6 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
| 143 | clp->cl_proto = cl_init->proto; | 143 | clp->cl_proto = cl_init->proto; |
| 144 | 144 | ||
| 145 | #ifdef CONFIG_NFS_V4 | 145 | #ifdef CONFIG_NFS_V4 |
| 146 | init_rwsem(&clp->cl_sem); | ||
| 147 | INIT_LIST_HEAD(&clp->cl_delegations); | 146 | INIT_LIST_HEAD(&clp->cl_delegations); |
| 148 | spin_lock_init(&clp->cl_lock); | 147 | spin_lock_init(&clp->cl_lock); |
| 149 | INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state); | 148 | INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state); |
| @@ -224,31 +223,54 @@ void nfs_put_client(struct nfs_client *clp) | |||
| 224 | } | 223 | } |
| 225 | } | 224 | } |
| 226 | 225 | ||
| 227 | static int nfs_sockaddr_match_ipaddr4(const struct sockaddr_in *sa1, | 226 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
| 228 | const struct sockaddr_in *sa2) | 227 | static const struct in6_addr *nfs_map_ipv4_addr(const struct sockaddr *sa, struct in6_addr *addr_mapped) |
| 229 | { | 228 | { |
| 230 | return sa1->sin_addr.s_addr == sa2->sin_addr.s_addr; | 229 | switch (sa->sa_family) { |
| 230 | default: | ||
| 231 | return NULL; | ||
| 232 | case AF_INET6: | ||
| 233 | return &((const struct sockaddr_in6 *)sa)->sin6_addr; | ||
| 234 | break; | ||
| 235 | case AF_INET: | ||
| 236 | ipv6_addr_set_v4mapped(((const struct sockaddr_in *)sa)->sin_addr.s_addr, | ||
| 237 | addr_mapped); | ||
| 238 | return addr_mapped; | ||
| 239 | } | ||
| 231 | } | 240 | } |
| 232 | 241 | ||
| 233 | static int nfs_sockaddr_match_ipaddr6(const struct sockaddr_in6 *sa1, | 242 | static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, |
| 234 | const struct sockaddr_in6 *sa2) | 243 | const struct sockaddr *sa2) |
| 244 | { | ||
| 245 | const struct in6_addr *addr1; | ||
| 246 | const struct in6_addr *addr2; | ||
| 247 | struct in6_addr addr1_mapped; | ||
| 248 | struct in6_addr addr2_mapped; | ||
| 249 | |||
| 250 | addr1 = nfs_map_ipv4_addr(sa1, &addr1_mapped); | ||
| 251 | if (likely(addr1 != NULL)) { | ||
| 252 | addr2 = nfs_map_ipv4_addr(sa2, &addr2_mapped); | ||
| 253 | if (likely(addr2 != NULL)) | ||
| 254 | return ipv6_addr_equal(addr1, addr2); | ||
| 255 | } | ||
| 256 | return 0; | ||
| 257 | } | ||
| 258 | #else | ||
| 259 | static int nfs_sockaddr_match_ipaddr4(const struct sockaddr_in *sa1, | ||
| 260 | const struct sockaddr_in *sa2) | ||
| 235 | { | 261 | { |
| 236 | return ipv6_addr_equal(&sa1->sin6_addr, &sa2->sin6_addr); | 262 | return sa1->sin_addr.s_addr == sa2->sin_addr.s_addr; |
| 237 | } | 263 | } |
| 238 | 264 | ||
| 239 | static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, | 265 | static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, |
| 240 | const struct sockaddr *sa2) | 266 | const struct sockaddr *sa2) |
| 241 | { | 267 | { |
| 242 | switch (sa1->sa_family) { | 268 | if (unlikely(sa1->sa_family != AF_INET || sa2->sa_family != AF_INET)) |
| 243 | case AF_INET: | 269 | return 0; |
| 244 | return nfs_sockaddr_match_ipaddr4((const struct sockaddr_in *)sa1, | 270 | return nfs_sockaddr_match_ipaddr4((const struct sockaddr_in *)sa1, |
| 245 | (const struct sockaddr_in *)sa2); | 271 | (const struct sockaddr_in *)sa2); |
| 246 | case AF_INET6: | ||
| 247 | return nfs_sockaddr_match_ipaddr6((const struct sockaddr_in6 *)sa1, | ||
| 248 | (const struct sockaddr_in6 *)sa2); | ||
| 249 | } | ||
| 250 | BUG(); | ||
| 251 | } | 272 | } |
| 273 | #endif | ||
| 252 | 274 | ||
| 253 | /* | 275 | /* |
| 254 | * Find a client by IP address and protocol version | 276 | * Find a client by IP address and protocol version |
| @@ -270,8 +292,6 @@ struct nfs_client *nfs_find_client(const struct sockaddr *addr, u32 nfsversion) | |||
| 270 | if (clp->rpc_ops->version != nfsversion) | 292 | if (clp->rpc_ops->version != nfsversion) |
| 271 | continue; | 293 | continue; |
| 272 | 294 | ||
| 273 | if (addr->sa_family != clap->sa_family) | ||
| 274 | continue; | ||
| 275 | /* Match only the IP address, not the port number */ | 295 | /* Match only the IP address, not the port number */ |
| 276 | if (!nfs_sockaddr_match_ipaddr(addr, clap)) | 296 | if (!nfs_sockaddr_match_ipaddr(addr, clap)) |
| 277 | continue; | 297 | continue; |
| @@ -305,8 +325,6 @@ struct nfs_client *nfs_find_client_next(struct nfs_client *clp) | |||
| 305 | if (clp->rpc_ops->version != nfsvers) | 325 | if (clp->rpc_ops->version != nfsvers) |
| 306 | continue; | 326 | continue; |
| 307 | 327 | ||
| 308 | if (sap->sa_family != clap->sa_family) | ||
| 309 | continue; | ||
| 310 | /* Match only the IP address, not the port number */ | 328 | /* Match only the IP address, not the port number */ |
| 311 | if (!nfs_sockaddr_match_ipaddr(sap, clap)) | 329 | if (!nfs_sockaddr_match_ipaddr(sap, clap)) |
| 312 | continue; | 330 | continue; |
| @@ -470,7 +488,7 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, | |||
| 470 | static int nfs_create_rpc_client(struct nfs_client *clp, | 488 | static int nfs_create_rpc_client(struct nfs_client *clp, |
| 471 | const struct rpc_timeout *timeparms, | 489 | const struct rpc_timeout *timeparms, |
| 472 | rpc_authflavor_t flavor, | 490 | rpc_authflavor_t flavor, |
| 473 | int flags) | 491 | int discrtry, int noresvport) |
| 474 | { | 492 | { |
| 475 | struct rpc_clnt *clnt = NULL; | 493 | struct rpc_clnt *clnt = NULL; |
| 476 | struct rpc_create_args args = { | 494 | struct rpc_create_args args = { |
| @@ -482,9 +500,13 @@ static int nfs_create_rpc_client(struct nfs_client *clp, | |||
| 482 | .program = &nfs_program, | 500 | .program = &nfs_program, |
| 483 | .version = clp->rpc_ops->version, | 501 | .version = clp->rpc_ops->version, |
| 484 | .authflavor = flavor, | 502 | .authflavor = flavor, |
| 485 | .flags = flags, | ||
| 486 | }; | 503 | }; |
| 487 | 504 | ||
| 505 | if (discrtry) | ||
| 506 | args.flags |= RPC_CLNT_CREATE_DISCRTRY; | ||
| 507 | if (noresvport) | ||
| 508 | args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; | ||
| 509 | |||
| 488 | if (!IS_ERR(clp->cl_rpcclient)) | 510 | if (!IS_ERR(clp->cl_rpcclient)) |
| 489 | return 0; | 511 | return 0; |
| 490 | 512 | ||
| @@ -522,6 +544,8 @@ static int nfs_start_lockd(struct nfs_server *server) | |||
| 522 | .protocol = server->flags & NFS_MOUNT_TCP ? | 544 | .protocol = server->flags & NFS_MOUNT_TCP ? |
| 523 | IPPROTO_TCP : IPPROTO_UDP, | 545 | IPPROTO_TCP : IPPROTO_UDP, |
| 524 | .nfs_version = clp->rpc_ops->version, | 546 | .nfs_version = clp->rpc_ops->version, |
| 547 | .noresvport = server->flags & NFS_MOUNT_NORESVPORT ? | ||
| 548 | 1 : 0, | ||
| 525 | }; | 549 | }; |
| 526 | 550 | ||
| 527 | if (nlm_init.nfs_version > 3) | 551 | if (nlm_init.nfs_version > 3) |
| @@ -623,7 +647,8 @@ static int nfs_init_client(struct nfs_client *clp, | |||
| 623 | * Create a client RPC handle for doing FSSTAT with UNIX auth only | 647 | * Create a client RPC handle for doing FSSTAT with UNIX auth only |
| 624 | * - RFC 2623, sec 2.3.2 | 648 | * - RFC 2623, sec 2.3.2 |
| 625 | */ | 649 | */ |
| 626 | error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX, 0); | 650 | error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX, |
| 651 | 0, data->flags & NFS_MOUNT_NORESVPORT); | ||
| 627 | if (error < 0) | 652 | if (error < 0) |
| 628 | goto error; | 653 | goto error; |
| 629 | nfs_mark_client_ready(clp, NFS_CS_READY); | 654 | nfs_mark_client_ready(clp, NFS_CS_READY); |
| @@ -965,7 +990,8 @@ error: | |||
| 965 | static int nfs4_init_client(struct nfs_client *clp, | 990 | static int nfs4_init_client(struct nfs_client *clp, |
| 966 | const struct rpc_timeout *timeparms, | 991 | const struct rpc_timeout *timeparms, |
| 967 | const char *ip_addr, | 992 | const char *ip_addr, |
| 968 | rpc_authflavor_t authflavour) | 993 | rpc_authflavor_t authflavour, |
| 994 | int flags) | ||
| 969 | { | 995 | { |
| 970 | int error; | 996 | int error; |
| 971 | 997 | ||
| @@ -979,7 +1005,7 @@ static int nfs4_init_client(struct nfs_client *clp, | |||
| 979 | clp->rpc_ops = &nfs_v4_clientops; | 1005 | clp->rpc_ops = &nfs_v4_clientops; |
| 980 | 1006 | ||
| 981 | error = nfs_create_rpc_client(clp, timeparms, authflavour, | 1007 | error = nfs_create_rpc_client(clp, timeparms, authflavour, |
| 982 | RPC_CLNT_CREATE_DISCRTRY); | 1008 | 1, flags & NFS_MOUNT_NORESVPORT); |
| 983 | if (error < 0) | 1009 | if (error < 0) |
| 984 | goto error; | 1010 | goto error; |
| 985 | memcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr)); | 1011 | memcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr)); |
| @@ -1030,7 +1056,8 @@ static int nfs4_set_client(struct nfs_server *server, | |||
| 1030 | error = PTR_ERR(clp); | 1056 | error = PTR_ERR(clp); |
| 1031 | goto error; | 1057 | goto error; |
| 1032 | } | 1058 | } |
| 1033 | error = nfs4_init_client(clp, timeparms, ip_addr, authflavour); | 1059 | error = nfs4_init_client(clp, timeparms, ip_addr, authflavour, |
| 1060 | server->flags); | ||
| 1034 | if (error < 0) | 1061 | if (error < 0) |
| 1035 | goto error_put; | 1062 | goto error_put; |
| 1036 | 1063 | ||
| @@ -1059,6 +1086,10 @@ static int nfs4_init_server(struct nfs_server *server, | |||
| 1059 | nfs_init_timeout_values(&timeparms, data->nfs_server.protocol, | 1086 | nfs_init_timeout_values(&timeparms, data->nfs_server.protocol, |
| 1060 | data->timeo, data->retrans); | 1087 | data->timeo, data->retrans); |
| 1061 | 1088 | ||
| 1089 | /* Initialise the client representation from the mount data */ | ||
| 1090 | server->flags = data->flags; | ||
| 1091 | server->caps |= NFS_CAP_ATOMIC_OPEN; | ||
| 1092 | |||
| 1062 | /* Get a client record */ | 1093 | /* Get a client record */ |
| 1063 | error = nfs4_set_client(server, | 1094 | error = nfs4_set_client(server, |
| 1064 | data->nfs_server.hostname, | 1095 | data->nfs_server.hostname, |
| @@ -1071,10 +1102,6 @@ static int nfs4_init_server(struct nfs_server *server, | |||
| 1071 | if (error < 0) | 1102 | if (error < 0) |
| 1072 | goto error; | 1103 | goto error; |
| 1073 | 1104 | ||
| 1074 | /* Initialise the client representation from the mount data */ | ||
| 1075 | server->flags = data->flags; | ||
| 1076 | server->caps |= NFS_CAP_ATOMIC_OPEN; | ||
| 1077 | |||
| 1078 | if (data->rsize) | 1105 | if (data->rsize) |
| 1079 | server->rsize = nfs_block_size(data->rsize, NULL); | 1106 | server->rsize = nfs_block_size(data->rsize, NULL); |
| 1080 | if (data->wsize) | 1107 | if (data->wsize) |
| @@ -1177,6 +1204,10 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
| 1177 | parent_server = NFS_SB(data->sb); | 1204 | parent_server = NFS_SB(data->sb); |
| 1178 | parent_client = parent_server->nfs_client; | 1205 | parent_client = parent_server->nfs_client; |
| 1179 | 1206 | ||
| 1207 | /* Initialise the client representation from the parent server */ | ||
| 1208 | nfs_server_copy_userdata(server, parent_server); | ||
| 1209 | server->caps |= NFS_CAP_ATOMIC_OPEN; | ||
| 1210 | |||
| 1180 | /* Get a client representation. | 1211 | /* Get a client representation. |
| 1181 | * Note: NFSv4 always uses TCP, */ | 1212 | * Note: NFSv4 always uses TCP, */ |
| 1182 | error = nfs4_set_client(server, data->hostname, | 1213 | error = nfs4_set_client(server, data->hostname, |
| @@ -1189,10 +1220,6 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
| 1189 | if (error < 0) | 1220 | if (error < 0) |
| 1190 | goto error; | 1221 | goto error; |
| 1191 | 1222 | ||
| 1192 | /* Initialise the client representation from the parent server */ | ||
| 1193 | nfs_server_copy_userdata(server, parent_server); | ||
| 1194 | server->caps |= NFS_CAP_ATOMIC_OPEN; | ||
| 1195 | |||
| 1196 | error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout, data->authflavor); | 1223 | error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout, data->authflavor); |
| 1197 | if (error < 0) | 1224 | if (error < 0) |
| 1198 | goto error; | 1225 | goto error; |
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index cc563cfa6940..968225a88015 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
| @@ -43,6 +43,27 @@ static void nfs_free_delegation(struct nfs_delegation *delegation) | |||
| 43 | put_rpccred(cred); | 43 | put_rpccred(cred); |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | void nfs_mark_delegation_referenced(struct nfs_delegation *delegation) | ||
| 47 | { | ||
| 48 | set_bit(NFS_DELEGATION_REFERENCED, &delegation->flags); | ||
| 49 | } | ||
| 50 | |||
| 51 | int nfs_have_delegation(struct inode *inode, fmode_t flags) | ||
| 52 | { | ||
| 53 | struct nfs_delegation *delegation; | ||
| 54 | int ret = 0; | ||
| 55 | |||
| 56 | flags &= FMODE_READ|FMODE_WRITE; | ||
| 57 | rcu_read_lock(); | ||
| 58 | delegation = rcu_dereference(NFS_I(inode)->delegation); | ||
| 59 | if (delegation != NULL && (delegation->type & flags) == flags) { | ||
| 60 | nfs_mark_delegation_referenced(delegation); | ||
| 61 | ret = 1; | ||
| 62 | } | ||
| 63 | rcu_read_unlock(); | ||
| 64 | return ret; | ||
| 65 | } | ||
| 66 | |||
| 46 | static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state) | 67 | static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state) |
| 47 | { | 68 | { |
| 48 | struct inode *inode = state->inode; | 69 | struct inode *inode = state->inode; |
| @@ -119,7 +140,7 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, st | |||
| 119 | delegation->maxsize = res->maxsize; | 140 | delegation->maxsize = res->maxsize; |
| 120 | oldcred = delegation->cred; | 141 | oldcred = delegation->cred; |
| 121 | delegation->cred = get_rpccred(cred); | 142 | delegation->cred = get_rpccred(cred); |
| 122 | delegation->flags &= ~NFS_DELEGATION_NEED_RECLAIM; | 143 | clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags); |
| 123 | NFS_I(inode)->delegation_state = delegation->type; | 144 | NFS_I(inode)->delegation_state = delegation->type; |
| 124 | smp_wmb(); | 145 | smp_wmb(); |
| 125 | put_rpccred(oldcred); | 146 | put_rpccred(oldcred); |
| @@ -134,19 +155,35 @@ static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation * | |||
| 134 | return res; | 155 | return res; |
| 135 | } | 156 | } |
| 136 | 157 | ||
| 158 | static struct inode *nfs_delegation_grab_inode(struct nfs_delegation *delegation) | ||
| 159 | { | ||
| 160 | struct inode *inode = NULL; | ||
| 161 | |||
| 162 | spin_lock(&delegation->lock); | ||
| 163 | if (delegation->inode != NULL) | ||
| 164 | inode = igrab(delegation->inode); | ||
| 165 | spin_unlock(&delegation->lock); | ||
| 166 | return inode; | ||
| 167 | } | ||
| 168 | |||
| 137 | static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid) | 169 | static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid) |
| 138 | { | 170 | { |
| 139 | struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation); | 171 | struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation); |
| 140 | 172 | ||
| 141 | if (delegation == NULL) | 173 | if (delegation == NULL) |
| 142 | goto nomatch; | 174 | goto nomatch; |
| 175 | spin_lock(&delegation->lock); | ||
| 143 | if (stateid != NULL && memcmp(delegation->stateid.data, stateid->data, | 176 | if (stateid != NULL && memcmp(delegation->stateid.data, stateid->data, |
| 144 | sizeof(delegation->stateid.data)) != 0) | 177 | sizeof(delegation->stateid.data)) != 0) |
| 145 | goto nomatch; | 178 | goto nomatch_unlock; |
| 146 | list_del_rcu(&delegation->super_list); | 179 | list_del_rcu(&delegation->super_list); |
| 180 | delegation->inode = NULL; | ||
| 147 | nfsi->delegation_state = 0; | 181 | nfsi->delegation_state = 0; |
| 148 | rcu_assign_pointer(nfsi->delegation, NULL); | 182 | rcu_assign_pointer(nfsi->delegation, NULL); |
| 183 | spin_unlock(&delegation->lock); | ||
| 149 | return delegation; | 184 | return delegation; |
| 185 | nomatch_unlock: | ||
| 186 | spin_unlock(&delegation->lock); | ||
| 150 | nomatch: | 187 | nomatch: |
| 151 | return NULL; | 188 | return NULL; |
| 152 | } | 189 | } |
| @@ -172,6 +209,8 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |||
| 172 | delegation->change_attr = nfsi->change_attr; | 209 | delegation->change_attr = nfsi->change_attr; |
| 173 | delegation->cred = get_rpccred(cred); | 210 | delegation->cred = get_rpccred(cred); |
| 174 | delegation->inode = inode; | 211 | delegation->inode = inode; |
| 212 | delegation->flags = 1<<NFS_DELEGATION_REFERENCED; | ||
| 213 | spin_lock_init(&delegation->lock); | ||
| 175 | 214 | ||
| 176 | spin_lock(&clp->cl_lock); | 215 | spin_lock(&clp->cl_lock); |
| 177 | if (rcu_dereference(nfsi->delegation) != NULL) { | 216 | if (rcu_dereference(nfsi->delegation) != NULL) { |
| @@ -226,22 +265,47 @@ static void nfs_msync_inode(struct inode *inode) | |||
| 226 | */ | 265 | */ |
| 227 | static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegation *delegation) | 266 | static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegation *delegation) |
| 228 | { | 267 | { |
| 229 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; | ||
| 230 | struct nfs_inode *nfsi = NFS_I(inode); | 268 | struct nfs_inode *nfsi = NFS_I(inode); |
| 231 | 269 | ||
| 232 | nfs_msync_inode(inode); | 270 | nfs_msync_inode(inode); |
| 233 | down_read(&clp->cl_sem); | ||
| 234 | /* Guard against new delegated open calls */ | 271 | /* Guard against new delegated open calls */ |
| 235 | down_write(&nfsi->rwsem); | 272 | down_write(&nfsi->rwsem); |
| 236 | nfs_delegation_claim_opens(inode, &delegation->stateid); | 273 | nfs_delegation_claim_opens(inode, &delegation->stateid); |
| 237 | up_write(&nfsi->rwsem); | 274 | up_write(&nfsi->rwsem); |
| 238 | up_read(&clp->cl_sem); | ||
| 239 | nfs_msync_inode(inode); | 275 | nfs_msync_inode(inode); |
| 240 | 276 | ||
| 241 | return nfs_do_return_delegation(inode, delegation, 1); | 277 | return nfs_do_return_delegation(inode, delegation, 1); |
| 242 | } | 278 | } |
| 243 | 279 | ||
| 244 | /* | 280 | /* |
| 281 | * Return all delegations that have been marked for return | ||
| 282 | */ | ||
| 283 | void nfs_client_return_marked_delegations(struct nfs_client *clp) | ||
| 284 | { | ||
| 285 | struct nfs_delegation *delegation; | ||
| 286 | struct inode *inode; | ||
| 287 | |||
| 288 | restart: | ||
| 289 | rcu_read_lock(); | ||
| 290 | list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { | ||
| 291 | if (!test_and_clear_bit(NFS_DELEGATION_RETURN, &delegation->flags)) | ||
| 292 | continue; | ||
| 293 | inode = nfs_delegation_grab_inode(delegation); | ||
| 294 | if (inode == NULL) | ||
| 295 | continue; | ||
| 296 | spin_lock(&clp->cl_lock); | ||
| 297 | delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); | ||
| 298 | spin_unlock(&clp->cl_lock); | ||
| 299 | rcu_read_unlock(); | ||
| 300 | if (delegation != NULL) | ||
| 301 | __nfs_inode_return_delegation(inode, delegation); | ||
| 302 | iput(inode); | ||
| 303 | goto restart; | ||
| 304 | } | ||
| 305 | rcu_read_unlock(); | ||
| 306 | } | ||
| 307 | |||
| 308 | /* | ||
| 245 | * This function returns the delegation without reclaiming opens | 309 | * This function returns the delegation without reclaiming opens |
| 246 | * or protecting against delegation reclaims. | 310 | * or protecting against delegation reclaims. |
| 247 | * It is therefore really only safe to be called from | 311 | * It is therefore really only safe to be called from |
| @@ -279,83 +343,55 @@ int nfs_inode_return_delegation(struct inode *inode) | |||
| 279 | return err; | 343 | return err; |
| 280 | } | 344 | } |
| 281 | 345 | ||
| 346 | static void nfs_mark_return_delegation(struct nfs_client *clp, struct nfs_delegation *delegation) | ||
| 347 | { | ||
| 348 | set_bit(NFS_DELEGATION_RETURN, &delegation->flags); | ||
| 349 | set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state); | ||
| 350 | } | ||
| 351 | |||
| 282 | /* | 352 | /* |
| 283 | * Return all delegations associated to a super block | 353 | * Return all delegations associated to a super block |
| 284 | */ | 354 | */ |
| 285 | void nfs_return_all_delegations(struct super_block *sb) | 355 | void nfs_super_return_all_delegations(struct super_block *sb) |
| 286 | { | 356 | { |
| 287 | struct nfs_client *clp = NFS_SB(sb)->nfs_client; | 357 | struct nfs_client *clp = NFS_SB(sb)->nfs_client; |
| 288 | struct nfs_delegation *delegation; | 358 | struct nfs_delegation *delegation; |
| 289 | struct inode *inode; | ||
| 290 | 359 | ||
| 291 | if (clp == NULL) | 360 | if (clp == NULL) |
| 292 | return; | 361 | return; |
| 293 | restart: | ||
| 294 | rcu_read_lock(); | 362 | rcu_read_lock(); |
| 295 | list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { | 363 | list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { |
| 296 | if (delegation->inode->i_sb != sb) | 364 | spin_lock(&delegation->lock); |
| 297 | continue; | 365 | if (delegation->inode != NULL && delegation->inode->i_sb == sb) |
| 298 | inode = igrab(delegation->inode); | 366 | set_bit(NFS_DELEGATION_RETURN, &delegation->flags); |
| 299 | if (inode == NULL) | 367 | spin_unlock(&delegation->lock); |
| 300 | continue; | ||
| 301 | spin_lock(&clp->cl_lock); | ||
| 302 | delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); | ||
| 303 | spin_unlock(&clp->cl_lock); | ||
| 304 | rcu_read_unlock(); | ||
| 305 | if (delegation != NULL) | ||
| 306 | __nfs_inode_return_delegation(inode, delegation); | ||
| 307 | iput(inode); | ||
| 308 | goto restart; | ||
| 309 | } | 368 | } |
| 310 | rcu_read_unlock(); | 369 | rcu_read_unlock(); |
| 370 | nfs_client_return_marked_delegations(clp); | ||
| 311 | } | 371 | } |
| 312 | 372 | ||
| 313 | static int nfs_do_expire_all_delegations(void *ptr) | 373 | static void nfs_client_mark_return_all_delegations(struct nfs_client *clp) |
| 314 | { | 374 | { |
| 315 | struct nfs_client *clp = ptr; | ||
| 316 | struct nfs_delegation *delegation; | 375 | struct nfs_delegation *delegation; |
| 317 | struct inode *inode; | ||
| 318 | 376 | ||
| 319 | allow_signal(SIGKILL); | ||
| 320 | restart: | ||
| 321 | if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) != 0) | ||
| 322 | goto out; | ||
| 323 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) | ||
| 324 | goto out; | ||
| 325 | rcu_read_lock(); | 377 | rcu_read_lock(); |
| 326 | list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { | 378 | list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { |
| 327 | inode = igrab(delegation->inode); | 379 | set_bit(NFS_DELEGATION_RETURN, &delegation->flags); |
| 328 | if (inode == NULL) | 380 | set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state); |
| 329 | continue; | ||
| 330 | spin_lock(&clp->cl_lock); | ||
| 331 | delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); | ||
| 332 | spin_unlock(&clp->cl_lock); | ||
| 333 | rcu_read_unlock(); | ||
| 334 | if (delegation) | ||
| 335 | __nfs_inode_return_delegation(inode, delegation); | ||
| 336 | iput(inode); | ||
| 337 | goto restart; | ||
| 338 | } | 381 | } |
| 339 | rcu_read_unlock(); | 382 | rcu_read_unlock(); |
| 340 | out: | 383 | } |
| 341 | nfs_put_client(clp); | 384 | |
| 342 | module_put_and_exit(0); | 385 | static void nfs_delegation_run_state_manager(struct nfs_client *clp) |
| 386 | { | ||
| 387 | if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) | ||
| 388 | nfs4_schedule_state_manager(clp); | ||
| 343 | } | 389 | } |
| 344 | 390 | ||
| 345 | void nfs_expire_all_delegations(struct nfs_client *clp) | 391 | void nfs_expire_all_delegations(struct nfs_client *clp) |
| 346 | { | 392 | { |
| 347 | struct task_struct *task; | 393 | nfs_client_mark_return_all_delegations(clp); |
| 348 | 394 | nfs_delegation_run_state_manager(clp); | |
| 349 | __module_get(THIS_MODULE); | ||
| 350 | atomic_inc(&clp->cl_count); | ||
| 351 | task = kthread_run(nfs_do_expire_all_delegations, clp, | ||
| 352 | "%s-delegreturn", | ||
| 353 | rpc_peeraddr2str(clp->cl_rpcclient, | ||
| 354 | RPC_DISPLAY_ADDR)); | ||
| 355 | if (!IS_ERR(task)) | ||
| 356 | return; | ||
| 357 | nfs_put_client(clp); | ||
| 358 | module_put(THIS_MODULE); | ||
| 359 | } | 395 | } |
| 360 | 396 | ||
| 361 | /* | 397 | /* |
| @@ -363,68 +399,29 @@ void nfs_expire_all_delegations(struct nfs_client *clp) | |||
| 363 | */ | 399 | */ |
| 364 | void nfs_handle_cb_pathdown(struct nfs_client *clp) | 400 | void nfs_handle_cb_pathdown(struct nfs_client *clp) |
| 365 | { | 401 | { |
| 366 | struct nfs_delegation *delegation; | ||
| 367 | struct inode *inode; | ||
| 368 | |||
| 369 | if (clp == NULL) | 402 | if (clp == NULL) |
| 370 | return; | 403 | return; |
| 371 | restart: | 404 | nfs_client_mark_return_all_delegations(clp); |
| 405 | } | ||
| 406 | |||
| 407 | static void nfs_client_mark_return_unreferenced_delegations(struct nfs_client *clp) | ||
| 408 | { | ||
| 409 | struct nfs_delegation *delegation; | ||
| 410 | |||
| 372 | rcu_read_lock(); | 411 | rcu_read_lock(); |
| 373 | list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { | 412 | list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { |
| 374 | inode = igrab(delegation->inode); | 413 | if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags)) |
| 375 | if (inode == NULL) | ||
| 376 | continue; | 414 | continue; |
| 377 | spin_lock(&clp->cl_lock); | 415 | set_bit(NFS_DELEGATION_RETURN, &delegation->flags); |
| 378 | delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); | 416 | set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state); |
| 379 | spin_unlock(&clp->cl_lock); | ||
| 380 | rcu_read_unlock(); | ||
| 381 | if (delegation != NULL) | ||
| 382 | __nfs_inode_return_delegation(inode, delegation); | ||
| 383 | iput(inode); | ||
| 384 | goto restart; | ||
| 385 | } | 417 | } |
| 386 | rcu_read_unlock(); | 418 | rcu_read_unlock(); |
| 387 | } | 419 | } |
| 388 | 420 | ||
| 389 | struct recall_threadargs { | 421 | void nfs_expire_unreferenced_delegations(struct nfs_client *clp) |
| 390 | struct inode *inode; | ||
| 391 | struct nfs_client *clp; | ||
| 392 | const nfs4_stateid *stateid; | ||
| 393 | |||
| 394 | struct completion started; | ||
| 395 | int result; | ||
| 396 | }; | ||
| 397 | |||
| 398 | static int recall_thread(void *data) | ||
| 399 | { | 422 | { |
| 400 | struct recall_threadargs *args = (struct recall_threadargs *)data; | 423 | nfs_client_mark_return_unreferenced_delegations(clp); |
| 401 | struct inode *inode = igrab(args->inode); | 424 | nfs_delegation_run_state_manager(clp); |
| 402 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; | ||
| 403 | struct nfs_inode *nfsi = NFS_I(inode); | ||
| 404 | struct nfs_delegation *delegation; | ||
| 405 | |||
| 406 | daemonize("nfsv4-delegreturn"); | ||
| 407 | |||
| 408 | nfs_msync_inode(inode); | ||
| 409 | down_read(&clp->cl_sem); | ||
| 410 | down_write(&nfsi->rwsem); | ||
| 411 | spin_lock(&clp->cl_lock); | ||
| 412 | delegation = nfs_detach_delegation_locked(nfsi, args->stateid); | ||
| 413 | if (delegation != NULL) | ||
| 414 | args->result = 0; | ||
| 415 | else | ||
| 416 | args->result = -ENOENT; | ||
| 417 | spin_unlock(&clp->cl_lock); | ||
| 418 | complete(&args->started); | ||
| 419 | nfs_delegation_claim_opens(inode, args->stateid); | ||
| 420 | up_write(&nfsi->rwsem); | ||
| 421 | up_read(&clp->cl_sem); | ||
| 422 | nfs_msync_inode(inode); | ||
| 423 | |||
| 424 | if (delegation != NULL) | ||
| 425 | nfs_do_return_delegation(inode, delegation, 1); | ||
| 426 | iput(inode); | ||
| 427 | module_put_and_exit(0); | ||
| 428 | } | 425 | } |
| 429 | 426 | ||
| 430 | /* | 427 | /* |
| @@ -432,22 +429,20 @@ static int recall_thread(void *data) | |||
| 432 | */ | 429 | */ |
| 433 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid) | 430 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid) |
| 434 | { | 431 | { |
| 435 | struct recall_threadargs data = { | 432 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; |
| 436 | .inode = inode, | 433 | struct nfs_delegation *delegation; |
| 437 | .stateid = stateid, | ||
| 438 | }; | ||
| 439 | int status; | ||
| 440 | 434 | ||
| 441 | init_completion(&data.started); | 435 | rcu_read_lock(); |
| 442 | __module_get(THIS_MODULE); | 436 | delegation = rcu_dereference(NFS_I(inode)->delegation); |
| 443 | status = kernel_thread(recall_thread, &data, CLONE_KERNEL); | 437 | if (delegation == NULL || memcmp(delegation->stateid.data, stateid->data, |
| 444 | if (status < 0) | 438 | sizeof(delegation->stateid.data)) != 0) { |
| 445 | goto out_module_put; | 439 | rcu_read_unlock(); |
| 446 | wait_for_completion(&data.started); | 440 | return -ENOENT; |
| 447 | return data.result; | 441 | } |
| 448 | out_module_put: | 442 | nfs_mark_return_delegation(clp, delegation); |
| 449 | module_put(THIS_MODULE); | 443 | rcu_read_unlock(); |
| 450 | return status; | 444 | nfs_delegation_run_state_manager(clp); |
| 445 | return 0; | ||
| 451 | } | 446 | } |
| 452 | 447 | ||
| 453 | /* | 448 | /* |
| @@ -459,10 +454,14 @@ struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs | |||
| 459 | struct inode *res = NULL; | 454 | struct inode *res = NULL; |
| 460 | rcu_read_lock(); | 455 | rcu_read_lock(); |
| 461 | list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { | 456 | list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { |
| 462 | if (nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) { | 457 | spin_lock(&delegation->lock); |
| 458 | if (delegation->inode != NULL && | ||
| 459 | nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) { | ||
| 463 | res = igrab(delegation->inode); | 460 | res = igrab(delegation->inode); |
| 464 | break; | ||
| 465 | } | 461 | } |
| 462 | spin_unlock(&delegation->lock); | ||
| 463 | if (res != NULL) | ||
| 464 | break; | ||
| 466 | } | 465 | } |
| 467 | rcu_read_unlock(); | 466 | rcu_read_unlock(); |
| 468 | return res; | 467 | return res; |
| @@ -476,7 +475,7 @@ void nfs_delegation_mark_reclaim(struct nfs_client *clp) | |||
| 476 | struct nfs_delegation *delegation; | 475 | struct nfs_delegation *delegation; |
| 477 | rcu_read_lock(); | 476 | rcu_read_lock(); |
| 478 | list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) | 477 | list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) |
| 479 | delegation->flags |= NFS_DELEGATION_NEED_RECLAIM; | 478 | set_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags); |
| 480 | rcu_read_unlock(); | 479 | rcu_read_unlock(); |
| 481 | } | 480 | } |
| 482 | 481 | ||
| @@ -486,17 +485,22 @@ void nfs_delegation_mark_reclaim(struct nfs_client *clp) | |||
| 486 | void nfs_delegation_reap_unclaimed(struct nfs_client *clp) | 485 | void nfs_delegation_reap_unclaimed(struct nfs_client *clp) |
| 487 | { | 486 | { |
| 488 | struct nfs_delegation *delegation; | 487 | struct nfs_delegation *delegation; |
| 488 | struct inode *inode; | ||
| 489 | restart: | 489 | restart: |
| 490 | rcu_read_lock(); | 490 | rcu_read_lock(); |
| 491 | list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { | 491 | list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { |
| 492 | if ((delegation->flags & NFS_DELEGATION_NEED_RECLAIM) == 0) | 492 | if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags) == 0) |
| 493 | continue; | ||
| 494 | inode = nfs_delegation_grab_inode(delegation); | ||
| 495 | if (inode == NULL) | ||
| 493 | continue; | 496 | continue; |
| 494 | spin_lock(&clp->cl_lock); | 497 | spin_lock(&clp->cl_lock); |
| 495 | delegation = nfs_detach_delegation_locked(NFS_I(delegation->inode), NULL); | 498 | delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); |
| 496 | spin_unlock(&clp->cl_lock); | 499 | spin_unlock(&clp->cl_lock); |
| 497 | rcu_read_unlock(); | 500 | rcu_read_unlock(); |
| 498 | if (delegation != NULL) | 501 | if (delegation != NULL) |
| 499 | nfs_free_delegation(delegation); | 502 | nfs_free_delegation(delegation); |
| 503 | iput(inode); | ||
| 500 | goto restart; | 504 | goto restart; |
| 501 | } | 505 | } |
| 502 | rcu_read_unlock(); | 506 | rcu_read_unlock(); |
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index f1c5e2a5d88e..09f383795174 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h | |||
| @@ -17,14 +17,20 @@ struct nfs_delegation { | |||
| 17 | struct rpc_cred *cred; | 17 | struct rpc_cred *cred; |
| 18 | struct inode *inode; | 18 | struct inode *inode; |
| 19 | nfs4_stateid stateid; | 19 | nfs4_stateid stateid; |
| 20 | int type; | 20 | fmode_t type; |
| 21 | #define NFS_DELEGATION_NEED_RECLAIM 1 | ||
| 22 | long flags; | ||
| 23 | loff_t maxsize; | 21 | loff_t maxsize; |
| 24 | __u64 change_attr; | 22 | __u64 change_attr; |
| 23 | unsigned long flags; | ||
| 24 | spinlock_t lock; | ||
| 25 | struct rcu_head rcu; | 25 | struct rcu_head rcu; |
| 26 | }; | 26 | }; |
| 27 | 27 | ||
| 28 | enum { | ||
| 29 | NFS_DELEGATION_NEED_RECLAIM = 0, | ||
| 30 | NFS_DELEGATION_RETURN, | ||
| 31 | NFS_DELEGATION_REFERENCED, | ||
| 32 | }; | ||
| 33 | |||
| 28 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); | 34 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); |
| 29 | void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); | 35 | void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); |
| 30 | int nfs_inode_return_delegation(struct inode *inode); | 36 | int nfs_inode_return_delegation(struct inode *inode); |
| @@ -32,9 +38,11 @@ int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *s | |||
| 32 | void nfs_inode_return_delegation_noreclaim(struct inode *inode); | 38 | void nfs_inode_return_delegation_noreclaim(struct inode *inode); |
| 33 | 39 | ||
| 34 | struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); | 40 | struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); |
| 35 | void nfs_return_all_delegations(struct super_block *sb); | 41 | void nfs_super_return_all_delegations(struct super_block *sb); |
| 36 | void nfs_expire_all_delegations(struct nfs_client *clp); | 42 | void nfs_expire_all_delegations(struct nfs_client *clp); |
| 43 | void nfs_expire_unreferenced_delegations(struct nfs_client *clp); | ||
| 37 | void nfs_handle_cb_pathdown(struct nfs_client *clp); | 44 | void nfs_handle_cb_pathdown(struct nfs_client *clp); |
| 45 | void nfs_client_return_marked_delegations(struct nfs_client *clp); | ||
| 38 | 46 | ||
| 39 | void nfs_delegation_mark_reclaim(struct nfs_client *clp); | 47 | void nfs_delegation_mark_reclaim(struct nfs_client *clp); |
| 40 | void nfs_delegation_reap_unclaimed(struct nfs_client *clp); | 48 | void nfs_delegation_reap_unclaimed(struct nfs_client *clp); |
| @@ -45,22 +53,11 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state | |||
| 45 | int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl); | 53 | int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl); |
| 46 | int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode); | 54 | int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode); |
| 47 | 55 | ||
| 48 | static inline int nfs_have_delegation(struct inode *inode, int flags) | 56 | void nfs_mark_delegation_referenced(struct nfs_delegation *delegation); |
| 49 | { | 57 | int nfs_have_delegation(struct inode *inode, fmode_t flags); |
| 50 | struct nfs_delegation *delegation; | ||
| 51 | int ret = 0; | ||
| 52 | |||
| 53 | flags &= FMODE_READ|FMODE_WRITE; | ||
| 54 | rcu_read_lock(); | ||
| 55 | delegation = rcu_dereference(NFS_I(inode)->delegation); | ||
| 56 | if (delegation != NULL && (delegation->type & flags) == flags) | ||
| 57 | ret = 1; | ||
| 58 | rcu_read_unlock(); | ||
| 59 | return ret; | ||
| 60 | } | ||
| 61 | 58 | ||
| 62 | #else | 59 | #else |
| 63 | static inline int nfs_have_delegation(struct inode *inode, int flags) | 60 | static inline int nfs_have_delegation(struct inode *inode, fmode_t flags) |
| 64 | { | 61 | { |
| 65 | return 0; | 62 | return 0; |
| 66 | } | 63 | } |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 3e64b98f3a93..e35c8199f82f 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
| @@ -799,6 +799,9 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) | |||
| 799 | goto out_bad; | 799 | goto out_bad; |
| 800 | } | 800 | } |
| 801 | 801 | ||
| 802 | if (nfs_have_delegation(inode, FMODE_READ)) | ||
| 803 | goto out_set_verifier; | ||
| 804 | |||
| 802 | /* Force a full look up iff the parent directory has changed */ | 805 | /* Force a full look up iff the parent directory has changed */ |
| 803 | if (!nfs_is_exclusive_create(dir, nd) && nfs_check_verifier(dir, dentry)) { | 806 | if (!nfs_is_exclusive_create(dir, nd) && nfs_check_verifier(dir, dentry)) { |
| 804 | if (nfs_lookup_verify_inode(inode, nd)) | 807 | if (nfs_lookup_verify_inode(inode, nd)) |
| @@ -817,6 +820,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) | |||
| 817 | if ((error = nfs_refresh_inode(inode, &fattr)) != 0) | 820 | if ((error = nfs_refresh_inode(inode, &fattr)) != 0) |
| 818 | goto out_bad; | 821 | goto out_bad; |
| 819 | 822 | ||
| 823 | out_set_verifier: | ||
| 820 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | 824 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
| 821 | out_valid: | 825 | out_valid: |
| 822 | dput(parent); | 826 | dput(parent); |
| @@ -973,7 +977,7 @@ struct dentry_operations nfs4_dentry_operations = { | |||
| 973 | * Use intent information to determine whether we need to substitute | 977 | * Use intent information to determine whether we need to substitute |
| 974 | * the NFSv4-style stateful OPEN for the LOOKUP call | 978 | * the NFSv4-style stateful OPEN for the LOOKUP call |
| 975 | */ | 979 | */ |
| 976 | static int is_atomic_open(struct inode *dir, struct nameidata *nd) | 980 | static int is_atomic_open(struct nameidata *nd) |
| 977 | { | 981 | { |
| 978 | if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_OPEN) == 0) | 982 | if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_OPEN) == 0) |
| 979 | return 0; | 983 | return 0; |
| @@ -996,7 +1000,7 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry | |||
| 996 | dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); | 1000 | dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); |
| 997 | 1001 | ||
| 998 | /* Check that we are indeed trying to open this file */ | 1002 | /* Check that we are indeed trying to open this file */ |
| 999 | if (!is_atomic_open(dir, nd)) | 1003 | if (!is_atomic_open(nd)) |
| 1000 | goto no_open; | 1004 | goto no_open; |
| 1001 | 1005 | ||
| 1002 | if (dentry->d_name.len > NFS_SERVER(dir)->namelen) { | 1006 | if (dentry->d_name.len > NFS_SERVER(dir)->namelen) { |
| @@ -1047,10 +1051,10 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
| 1047 | struct inode *dir; | 1051 | struct inode *dir; |
| 1048 | int openflags, ret = 0; | 1052 | int openflags, ret = 0; |
| 1049 | 1053 | ||
| 1054 | if (!is_atomic_open(nd)) | ||
| 1055 | goto no_open; | ||
| 1050 | parent = dget_parent(dentry); | 1056 | parent = dget_parent(dentry); |
| 1051 | dir = parent->d_inode; | 1057 | dir = parent->d_inode; |
| 1052 | if (!is_atomic_open(dir, nd)) | ||
| 1053 | goto no_open; | ||
| 1054 | /* We can't create new files in nfs_open_revalidate(), so we | 1058 | /* We can't create new files in nfs_open_revalidate(), so we |
| 1055 | * optimize away revalidation of negative dentries. | 1059 | * optimize away revalidation of negative dentries. |
| 1056 | */ | 1060 | */ |
| @@ -1062,11 +1066,11 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
| 1062 | 1066 | ||
| 1063 | /* NFS only supports OPEN on regular files */ | 1067 | /* NFS only supports OPEN on regular files */ |
| 1064 | if (!S_ISREG(inode->i_mode)) | 1068 | if (!S_ISREG(inode->i_mode)) |
| 1065 | goto no_open; | 1069 | goto no_open_dput; |
| 1066 | openflags = nd->intent.open.flags; | 1070 | openflags = nd->intent.open.flags; |
| 1067 | /* We cannot do exclusive creation on a positive dentry */ | 1071 | /* We cannot do exclusive creation on a positive dentry */ |
| 1068 | if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) | 1072 | if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) |
| 1069 | goto no_open; | 1073 | goto no_open_dput; |
| 1070 | /* We can't create new files, or truncate existing ones here */ | 1074 | /* We can't create new files, or truncate existing ones here */ |
| 1071 | openflags &= ~(O_CREAT|O_TRUNC); | 1075 | openflags &= ~(O_CREAT|O_TRUNC); |
| 1072 | 1076 | ||
| @@ -1081,10 +1085,9 @@ out: | |||
| 1081 | if (!ret) | 1085 | if (!ret) |
| 1082 | d_drop(dentry); | 1086 | d_drop(dentry); |
| 1083 | return ret; | 1087 | return ret; |
| 1084 | no_open: | 1088 | no_open_dput: |
| 1085 | dput(parent); | 1089 | dput(parent); |
| 1086 | if (inode != NULL && nfs_have_delegation(inode, FMODE_READ)) | 1090 | no_open: |
| 1087 | return 1; | ||
| 1088 | return nfs_lookup_revalidate(dentry, nd); | 1091 | return nfs_lookup_revalidate(dentry, nd); |
| 1089 | } | 1092 | } |
| 1090 | #endif /* CONFIG_NFSV4 */ | 1093 | #endif /* CONFIG_NFSV4 */ |
| @@ -1794,7 +1797,8 @@ static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, str | |||
| 1794 | cache = nfs_access_search_rbtree(inode, cred); | 1797 | cache = nfs_access_search_rbtree(inode, cred); |
| 1795 | if (cache == NULL) | 1798 | if (cache == NULL) |
| 1796 | goto out; | 1799 | goto out; |
| 1797 | if (!time_in_range(jiffies, cache->jiffies, cache->jiffies + nfsi->attrtimeo)) | 1800 | if (!nfs_have_delegation(inode, FMODE_READ) && |
| 1801 | !time_in_range_open(jiffies, cache->jiffies, cache->jiffies + nfsi->attrtimeo)) | ||
| 1798 | goto out_stale; | 1802 | goto out_stale; |
| 1799 | res->jiffies = cache->jiffies; | 1803 | res->jiffies = cache->jiffies; |
| 1800 | res->cred = cache->cred; | 1804 | res->cred = cache->cred; |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index d22eb383e1cf..0c381686171e 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
| @@ -592,7 +592,7 @@ static void nfs_file_set_open_context(struct file *filp, struct nfs_open_context | |||
| 592 | /* | 592 | /* |
| 593 | * Given an inode, search for an open context with the desired characteristics | 593 | * Given an inode, search for an open context with the desired characteristics |
| 594 | */ | 594 | */ |
| 595 | struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, int mode) | 595 | struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, fmode_t mode) |
| 596 | { | 596 | { |
| 597 | struct nfs_inode *nfsi = NFS_I(inode); | 597 | struct nfs_inode *nfsi = NFS_I(inode); |
| 598 | struct nfs_open_context *pos, *ctx = NULL; | 598 | struct nfs_open_context *pos, *ctx = NULL; |
| @@ -712,14 +712,7 @@ int nfs_attribute_timeout(struct inode *inode) | |||
| 712 | 712 | ||
| 713 | if (nfs_have_delegation(inode, FMODE_READ)) | 713 | if (nfs_have_delegation(inode, FMODE_READ)) |
| 714 | return 0; | 714 | return 0; |
| 715 | /* | 715 | return !time_in_range_open(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo); |
| 716 | * Special case: if the attribute timeout is set to 0, then always | ||
| 717 | * treat the cache as having expired (unless holding | ||
| 718 | * a delegation). | ||
| 719 | */ | ||
| 720 | if (nfsi->attrtimeo == 0) | ||
| 721 | return 1; | ||
| 722 | return !time_in_range(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo); | ||
| 723 | } | 716 | } |
| 724 | 717 | ||
| 725 | /** | 718 | /** |
| @@ -1182,7 +1175,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
| 1182 | nfsi->attrtimeo_timestamp = now; | 1175 | nfsi->attrtimeo_timestamp = now; |
| 1183 | nfsi->attr_gencount = nfs_inc_attr_generation_counter(); | 1176 | nfsi->attr_gencount = nfs_inc_attr_generation_counter(); |
| 1184 | } else { | 1177 | } else { |
| 1185 | if (!time_in_range(now, nfsi->attrtimeo_timestamp, nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) { | 1178 | if (!time_in_range_open(now, nfsi->attrtimeo_timestamp, nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) { |
| 1186 | if ((nfsi->attrtimeo <<= 1) > NFS_MAXATTRTIMEO(inode)) | 1179 | if ((nfsi->attrtimeo <<= 1) > NFS_MAXATTRTIMEO(inode)) |
| 1187 | nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode); | 1180 | nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode); |
| 1188 | nfsi->attrtimeo_timestamp = now; | 1181 | nfsi->attrtimeo_timestamp = now; |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index d212ee41caf2..340ede8f608f 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
| @@ -63,6 +63,20 @@ struct nfs_parsed_mount_data { | |||
| 63 | struct security_mnt_opts lsm_opts; | 63 | struct security_mnt_opts lsm_opts; |
| 64 | }; | 64 | }; |
| 65 | 65 | ||
| 66 | /* mount_clnt.c */ | ||
| 67 | struct nfs_mount_request { | ||
| 68 | struct sockaddr *sap; | ||
| 69 | size_t salen; | ||
| 70 | char *hostname; | ||
| 71 | char *dirpath; | ||
| 72 | u32 version; | ||
| 73 | unsigned short protocol; | ||
| 74 | struct nfs_fh *fh; | ||
| 75 | int noresvport; | ||
| 76 | }; | ||
| 77 | |||
| 78 | extern int nfs_mount(struct nfs_mount_request *info); | ||
| 79 | |||
| 66 | /* client.c */ | 80 | /* client.c */ |
| 67 | extern struct rpc_program nfs_program; | 81 | extern struct rpc_program nfs_program; |
| 68 | 82 | ||
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 086a6830d785..ca905a5bb1ba 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c | |||
| @@ -29,47 +29,43 @@ struct mnt_fhstatus { | |||
| 29 | 29 | ||
| 30 | /** | 30 | /** |
| 31 | * nfs_mount - Obtain an NFS file handle for the given host and path | 31 | * nfs_mount - Obtain an NFS file handle for the given host and path |
| 32 | * @addr: pointer to server's address | 32 | * @info: pointer to mount request arguments |
| 33 | * @len: size of server's address | ||
| 34 | * @hostname: name of server host, or NULL | ||
| 35 | * @path: pointer to string containing export path to mount | ||
| 36 | * @version: mount version to use for this request | ||
| 37 | * @protocol: transport protocol to use for thie request | ||
| 38 | * @fh: pointer to location to place returned file handle | ||
| 39 | * | 33 | * |
| 40 | * Uses default timeout parameters specified by underlying transport. | 34 | * Uses default timeout parameters specified by underlying transport. |
| 41 | */ | 35 | */ |
| 42 | int nfs_mount(struct sockaddr *addr, size_t len, char *hostname, char *path, | 36 | int nfs_mount(struct nfs_mount_request *info) |
| 43 | int version, int protocol, struct nfs_fh *fh) | ||
| 44 | { | 37 | { |
| 45 | struct mnt_fhstatus result = { | 38 | struct mnt_fhstatus result = { |
| 46 | .fh = fh | 39 | .fh = info->fh |
| 47 | }; | 40 | }; |
| 48 | struct rpc_message msg = { | 41 | struct rpc_message msg = { |
| 49 | .rpc_argp = path, | 42 | .rpc_argp = info->dirpath, |
| 50 | .rpc_resp = &result, | 43 | .rpc_resp = &result, |
| 51 | }; | 44 | }; |
| 52 | struct rpc_create_args args = { | 45 | struct rpc_create_args args = { |
| 53 | .protocol = protocol, | 46 | .protocol = info->protocol, |
| 54 | .address = addr, | 47 | .address = info->sap, |
| 55 | .addrsize = len, | 48 | .addrsize = info->salen, |
| 56 | .servername = hostname, | 49 | .servername = info->hostname, |
| 57 | .program = &mnt_program, | 50 | .program = &mnt_program, |
| 58 | .version = version, | 51 | .version = info->version, |
| 59 | .authflavor = RPC_AUTH_UNIX, | 52 | .authflavor = RPC_AUTH_UNIX, |
| 60 | .flags = 0, | ||
| 61 | }; | 53 | }; |
| 62 | struct rpc_clnt *mnt_clnt; | 54 | struct rpc_clnt *mnt_clnt; |
| 63 | int status; | 55 | int status; |
| 64 | 56 | ||
| 65 | dprintk("NFS: sending MNT request for %s:%s\n", | 57 | dprintk("NFS: sending MNT request for %s:%s\n", |
| 66 | (hostname ? hostname : "server"), path); | 58 | (info->hostname ? info->hostname : "server"), |
| 59 | info->dirpath); | ||
| 60 | |||
| 61 | if (info->noresvport) | ||
| 62 | args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; | ||
| 67 | 63 | ||
| 68 | mnt_clnt = rpc_create(&args); | 64 | mnt_clnt = rpc_create(&args); |
| 69 | if (IS_ERR(mnt_clnt)) | 65 | if (IS_ERR(mnt_clnt)) |
| 70 | goto out_clnt_err; | 66 | goto out_clnt_err; |
| 71 | 67 | ||
| 72 | if (version == NFS_MNT3_VERSION) | 68 | if (info->version == NFS_MNT3_VERSION) |
| 73 | msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT]; | 69 | msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT]; |
| 74 | else | 70 | else |
| 75 | msg.rpc_proc = &mnt_clnt->cl_procinfo[MNTPROC_MNT]; | 71 | msg.rpc_proc = &mnt_clnt->cl_procinfo[MNTPROC_MNT]; |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index ea790645fda6..4e4d33204376 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
| @@ -38,8 +38,12 @@ struct idmap; | |||
| 38 | ((err) != NFSERR_NOFILEHANDLE)) | 38 | ((err) != NFSERR_NOFILEHANDLE)) |
| 39 | 39 | ||
| 40 | enum nfs4_client_state { | 40 | enum nfs4_client_state { |
| 41 | NFS4CLNT_STATE_RECOVER = 0, | 41 | NFS4CLNT_MANAGER_RUNNING = 0, |
| 42 | NFS4CLNT_CHECK_LEASE, | ||
| 42 | NFS4CLNT_LEASE_EXPIRED, | 43 | NFS4CLNT_LEASE_EXPIRED, |
| 44 | NFS4CLNT_RECLAIM_REBOOT, | ||
| 45 | NFS4CLNT_RECLAIM_NOGRACE, | ||
| 46 | NFS4CLNT_DELEGRETURN, | ||
| 43 | }; | 47 | }; |
| 44 | 48 | ||
| 45 | /* | 49 | /* |
| @@ -90,12 +94,18 @@ struct nfs4_state_owner { | |||
| 90 | 94 | ||
| 91 | spinlock_t so_lock; | 95 | spinlock_t so_lock; |
| 92 | atomic_t so_count; | 96 | atomic_t so_count; |
| 97 | unsigned long so_flags; | ||
| 93 | struct list_head so_states; | 98 | struct list_head so_states; |
| 94 | struct list_head so_delegations; | 99 | struct list_head so_delegations; |
| 95 | struct nfs_seqid_counter so_seqid; | 100 | struct nfs_seqid_counter so_seqid; |
| 96 | struct rpc_sequence so_sequence; | 101 | struct rpc_sequence so_sequence; |
| 97 | }; | 102 | }; |
| 98 | 103 | ||
| 104 | enum { | ||
| 105 | NFS_OWNER_RECLAIM_REBOOT, | ||
| 106 | NFS_OWNER_RECLAIM_NOGRACE | ||
| 107 | }; | ||
| 108 | |||
| 99 | /* | 109 | /* |
| 100 | * struct nfs4_state maintains the client-side state for a given | 110 | * struct nfs4_state maintains the client-side state for a given |
| 101 | * (state_owner,inode) tuple (OPEN) or state_owner (LOCK). | 111 | * (state_owner,inode) tuple (OPEN) or state_owner (LOCK). |
| @@ -128,6 +138,8 @@ enum { | |||
| 128 | NFS_O_RDONLY_STATE, /* OPEN stateid has read-only state */ | 138 | NFS_O_RDONLY_STATE, /* OPEN stateid has read-only state */ |
| 129 | NFS_O_WRONLY_STATE, /* OPEN stateid has write-only state */ | 139 | NFS_O_WRONLY_STATE, /* OPEN stateid has write-only state */ |
| 130 | NFS_O_RDWR_STATE, /* OPEN stateid has read/write state */ | 140 | NFS_O_RDWR_STATE, /* OPEN stateid has read/write state */ |
| 141 | NFS_STATE_RECLAIM_REBOOT, /* OPEN stateid server rebooted */ | ||
| 142 | NFS_STATE_RECLAIM_NOGRACE, /* OPEN stateid needs to recover state */ | ||
| 131 | }; | 143 | }; |
| 132 | 144 | ||
| 133 | struct nfs4_state { | 145 | struct nfs4_state { |
| @@ -149,7 +161,7 @@ struct nfs4_state { | |||
| 149 | unsigned int n_rdonly; /* Number of read-only references */ | 161 | unsigned int n_rdonly; /* Number of read-only references */ |
| 150 | unsigned int n_wronly; /* Number of write-only references */ | 162 | unsigned int n_wronly; /* Number of write-only references */ |
| 151 | unsigned int n_rdwr; /* Number of read/write references */ | 163 | unsigned int n_rdwr; /* Number of read/write references */ |
| 152 | int state; /* State on the server (R,W, or RW) */ | 164 | fmode_t state; /* State on the server (R,W, or RW) */ |
| 153 | atomic_t count; | 165 | atomic_t count; |
| 154 | }; | 166 | }; |
| 155 | 167 | ||
| @@ -157,9 +169,12 @@ struct nfs4_state { | |||
| 157 | struct nfs4_exception { | 169 | struct nfs4_exception { |
| 158 | long timeout; | 170 | long timeout; |
| 159 | int retry; | 171 | int retry; |
| 172 | struct nfs4_state *state; | ||
| 160 | }; | 173 | }; |
| 161 | 174 | ||
| 162 | struct nfs4_state_recovery_ops { | 175 | struct nfs4_state_recovery_ops { |
| 176 | int owner_flag_bit; | ||
| 177 | int state_flag_bit; | ||
| 163 | int (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *); | 178 | int (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *); |
| 164 | int (*recover_lock)(struct nfs4_state *, struct file_lock *); | 179 | int (*recover_lock)(struct nfs4_state *, struct file_lock *); |
| 165 | }; | 180 | }; |
| @@ -174,7 +189,6 @@ extern ssize_t nfs4_listxattr(struct dentry *, char *, size_t); | |||
| 174 | 189 | ||
| 175 | 190 | ||
| 176 | /* nfs4proc.c */ | 191 | /* nfs4proc.c */ |
| 177 | extern int nfs4_map_errors(int err); | ||
| 178 | extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *); | 192 | extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *); |
| 179 | extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *); | 193 | extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *); |
| 180 | extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); | 194 | extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); |
| @@ -187,7 +201,7 @@ extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | |||
| 187 | struct nfs4_fs_locations *fs_locations, struct page *page); | 201 | struct nfs4_fs_locations *fs_locations, struct page *page); |
| 188 | 202 | ||
| 189 | extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops; | 203 | extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops; |
| 190 | extern struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops; | 204 | extern struct nfs4_state_recovery_ops nfs4_nograce_recovery_ops; |
| 191 | 205 | ||
| 192 | extern const u32 nfs4_fattr_bitmap[2]; | 206 | extern const u32 nfs4_fattr_bitmap[2]; |
| 193 | extern const u32 nfs4_statfs_bitmap[2]; | 207 | extern const u32 nfs4_statfs_bitmap[2]; |
| @@ -202,16 +216,18 @@ extern void nfs4_kill_renewd(struct nfs_client *); | |||
| 202 | extern void nfs4_renew_state(struct work_struct *); | 216 | extern void nfs4_renew_state(struct work_struct *); |
| 203 | 217 | ||
| 204 | /* nfs4state.c */ | 218 | /* nfs4state.c */ |
| 205 | struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp); | 219 | struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp); |
| 206 | 220 | ||
| 207 | extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); | 221 | extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); |
| 208 | extern void nfs4_put_state_owner(struct nfs4_state_owner *); | 222 | extern void nfs4_put_state_owner(struct nfs4_state_owner *); |
| 209 | extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *); | 223 | extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *); |
| 210 | extern void nfs4_put_open_state(struct nfs4_state *); | 224 | extern void nfs4_put_open_state(struct nfs4_state *); |
| 211 | extern void nfs4_close_state(struct path *, struct nfs4_state *, mode_t); | 225 | extern void nfs4_close_state(struct path *, struct nfs4_state *, fmode_t); |
| 212 | extern void nfs4_close_sync(struct path *, struct nfs4_state *, mode_t); | 226 | extern void nfs4_close_sync(struct path *, struct nfs4_state *, fmode_t); |
| 213 | extern void nfs4_state_set_mode_locked(struct nfs4_state *, mode_t); | 227 | extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t); |
| 214 | extern void nfs4_schedule_state_recovery(struct nfs_client *); | 228 | extern void nfs4_schedule_state_recovery(struct nfs_client *); |
| 229 | extern void nfs4_schedule_state_manager(struct nfs_client *); | ||
| 230 | extern int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state); | ||
| 215 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); | 231 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); |
| 216 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); | 232 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); |
| 217 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); | 233 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 83e700a2b0c0..8dde84b988d9 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
| @@ -62,14 +62,12 @@ | |||
| 62 | struct nfs4_opendata; | 62 | struct nfs4_opendata; |
| 63 | static int _nfs4_proc_open(struct nfs4_opendata *data); | 63 | static int _nfs4_proc_open(struct nfs4_opendata *data); |
| 64 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); | 64 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); |
| 65 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); | 65 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *); |
| 66 | static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); | ||
| 67 | static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp); | ||
| 68 | static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); | 66 | static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); |
| 69 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr); | 67 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr); |
| 70 | 68 | ||
| 71 | /* Prevent leaks of NFSv4 errors into userland */ | 69 | /* Prevent leaks of NFSv4 errors into userland */ |
| 72 | int nfs4_map_errors(int err) | 70 | static int nfs4_map_errors(int err) |
| 73 | { | 71 | { |
| 74 | if (err < -1000) { | 72 | if (err < -1000) { |
| 75 | dprintk("%s could not handle NFSv4 error %d\n", | 73 | dprintk("%s could not handle NFSv4 error %d\n", |
| @@ -195,6 +193,83 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent | |||
| 195 | kunmap_atomic(start, KM_USER0); | 193 | kunmap_atomic(start, KM_USER0); |
| 196 | } | 194 | } |
| 197 | 195 | ||
| 196 | static int nfs4_wait_bit_killable(void *word) | ||
| 197 | { | ||
| 198 | if (fatal_signal_pending(current)) | ||
| 199 | return -ERESTARTSYS; | ||
| 200 | schedule(); | ||
| 201 | return 0; | ||
| 202 | } | ||
| 203 | |||
| 204 | static int nfs4_wait_clnt_recover(struct nfs_client *clp) | ||
| 205 | { | ||
| 206 | int res; | ||
| 207 | |||
| 208 | might_sleep(); | ||
| 209 | |||
| 210 | res = wait_on_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING, | ||
| 211 | nfs4_wait_bit_killable, TASK_KILLABLE); | ||
| 212 | return res; | ||
| 213 | } | ||
| 214 | |||
| 215 | static int nfs4_delay(struct rpc_clnt *clnt, long *timeout) | ||
| 216 | { | ||
| 217 | int res = 0; | ||
| 218 | |||
| 219 | might_sleep(); | ||
| 220 | |||
| 221 | if (*timeout <= 0) | ||
| 222 | *timeout = NFS4_POLL_RETRY_MIN; | ||
| 223 | if (*timeout > NFS4_POLL_RETRY_MAX) | ||
| 224 | *timeout = NFS4_POLL_RETRY_MAX; | ||
| 225 | schedule_timeout_killable(*timeout); | ||
| 226 | if (fatal_signal_pending(current)) | ||
| 227 | res = -ERESTARTSYS; | ||
| 228 | *timeout <<= 1; | ||
| 229 | return res; | ||
| 230 | } | ||
| 231 | |||
| 232 | /* This is the error handling routine for processes that are allowed | ||
| 233 | * to sleep. | ||
| 234 | */ | ||
| 235 | static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception) | ||
| 236 | { | ||
| 237 | struct nfs_client *clp = server->nfs_client; | ||
| 238 | struct nfs4_state *state = exception->state; | ||
| 239 | int ret = errorcode; | ||
| 240 | |||
| 241 | exception->retry = 0; | ||
| 242 | switch(errorcode) { | ||
| 243 | case 0: | ||
| 244 | return 0; | ||
| 245 | case -NFS4ERR_ADMIN_REVOKED: | ||
| 246 | case -NFS4ERR_BAD_STATEID: | ||
| 247 | case -NFS4ERR_OPENMODE: | ||
| 248 | if (state == NULL) | ||
| 249 | break; | ||
| 250 | nfs4_state_mark_reclaim_nograce(clp, state); | ||
| 251 | case -NFS4ERR_STALE_CLIENTID: | ||
| 252 | case -NFS4ERR_STALE_STATEID: | ||
| 253 | case -NFS4ERR_EXPIRED: | ||
| 254 | nfs4_schedule_state_recovery(clp); | ||
| 255 | ret = nfs4_wait_clnt_recover(clp); | ||
| 256 | if (ret == 0) | ||
| 257 | exception->retry = 1; | ||
| 258 | break; | ||
| 259 | case -NFS4ERR_FILE_OPEN: | ||
| 260 | case -NFS4ERR_GRACE: | ||
| 261 | case -NFS4ERR_DELAY: | ||
| 262 | ret = nfs4_delay(server->client, &exception->timeout); | ||
| 263 | if (ret != 0) | ||
| 264 | break; | ||
| 265 | case -NFS4ERR_OLD_STATEID: | ||
| 266 | exception->retry = 1; | ||
| 267 | } | ||
| 268 | /* We failed to handle the error */ | ||
| 269 | return nfs4_map_errors(ret); | ||
| 270 | } | ||
| 271 | |||
| 272 | |||
| 198 | static void renew_lease(const struct nfs_server *server, unsigned long timestamp) | 273 | static void renew_lease(const struct nfs_server *server, unsigned long timestamp) |
| 199 | { | 274 | { |
| 200 | struct nfs_client *clp = server->nfs_client; | 275 | struct nfs_client *clp = server->nfs_client; |
| @@ -248,7 +323,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p) | |||
| 248 | } | 323 | } |
| 249 | 324 | ||
| 250 | static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | 325 | static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, |
| 251 | struct nfs4_state_owner *sp, int flags, | 326 | struct nfs4_state_owner *sp, fmode_t fmode, int flags, |
| 252 | const struct iattr *attrs) | 327 | const struct iattr *attrs) |
| 253 | { | 328 | { |
| 254 | struct dentry *parent = dget_parent(path->dentry); | 329 | struct dentry *parent = dget_parent(path->dentry); |
| @@ -268,7 +343,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | |||
| 268 | p->owner = sp; | 343 | p->owner = sp; |
| 269 | atomic_inc(&sp->so_count); | 344 | atomic_inc(&sp->so_count); |
| 270 | p->o_arg.fh = NFS_FH(dir); | 345 | p->o_arg.fh = NFS_FH(dir); |
| 271 | p->o_arg.open_flags = flags, | 346 | p->o_arg.open_flags = flags; |
| 347 | p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE); | ||
| 272 | p->o_arg.clientid = server->nfs_client->cl_clientid; | 348 | p->o_arg.clientid = server->nfs_client->cl_clientid; |
| 273 | p->o_arg.id = sp->so_owner_id.id; | 349 | p->o_arg.id = sp->so_owner_id.id; |
| 274 | p->o_arg.name = &p->path.dentry->d_name; | 350 | p->o_arg.name = &p->path.dentry->d_name; |
| @@ -324,10 +400,13 @@ static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task) | |||
| 324 | return ret; | 400 | return ret; |
| 325 | } | 401 | } |
| 326 | 402 | ||
| 327 | static int can_open_cached(struct nfs4_state *state, int mode) | 403 | static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode) |
| 328 | { | 404 | { |
| 329 | int ret = 0; | 405 | int ret = 0; |
| 330 | switch (mode & (FMODE_READ|FMODE_WRITE|O_EXCL)) { | 406 | |
| 407 | if (open_mode & O_EXCL) | ||
| 408 | goto out; | ||
| 409 | switch (mode & (FMODE_READ|FMODE_WRITE)) { | ||
| 331 | case FMODE_READ: | 410 | case FMODE_READ: |
| 332 | ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0; | 411 | ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0; |
| 333 | break; | 412 | break; |
| @@ -337,21 +416,23 @@ static int can_open_cached(struct nfs4_state *state, int mode) | |||
| 337 | case FMODE_READ|FMODE_WRITE: | 416 | case FMODE_READ|FMODE_WRITE: |
| 338 | ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; | 417 | ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; |
| 339 | } | 418 | } |
| 419 | out: | ||
| 340 | return ret; | 420 | return ret; |
| 341 | } | 421 | } |
| 342 | 422 | ||
| 343 | static int can_open_delegated(struct nfs_delegation *delegation, mode_t open_flags) | 423 | static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode) |
| 344 | { | 424 | { |
| 345 | if ((delegation->type & open_flags) != open_flags) | 425 | if ((delegation->type & fmode) != fmode) |
| 346 | return 0; | 426 | return 0; |
| 347 | if (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) | 427 | if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags)) |
| 348 | return 0; | 428 | return 0; |
| 429 | nfs_mark_delegation_referenced(delegation); | ||
| 349 | return 1; | 430 | return 1; |
| 350 | } | 431 | } |
| 351 | 432 | ||
| 352 | static void update_open_stateflags(struct nfs4_state *state, mode_t open_flags) | 433 | static void update_open_stateflags(struct nfs4_state *state, fmode_t fmode) |
| 353 | { | 434 | { |
| 354 | switch (open_flags) { | 435 | switch (fmode) { |
| 355 | case FMODE_WRITE: | 436 | case FMODE_WRITE: |
| 356 | state->n_wronly++; | 437 | state->n_wronly++; |
| 357 | break; | 438 | break; |
| @@ -361,15 +442,15 @@ static void update_open_stateflags(struct nfs4_state *state, mode_t open_flags) | |||
| 361 | case FMODE_READ|FMODE_WRITE: | 442 | case FMODE_READ|FMODE_WRITE: |
| 362 | state->n_rdwr++; | 443 | state->n_rdwr++; |
| 363 | } | 444 | } |
| 364 | nfs4_state_set_mode_locked(state, state->state | open_flags); | 445 | nfs4_state_set_mode_locked(state, state->state | fmode); |
| 365 | } | 446 | } |
| 366 | 447 | ||
| 367 | static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) | 448 | static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode) |
| 368 | { | 449 | { |
| 369 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) | 450 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) |
| 370 | memcpy(state->stateid.data, stateid->data, sizeof(state->stateid.data)); | 451 | memcpy(state->stateid.data, stateid->data, sizeof(state->stateid.data)); |
| 371 | memcpy(state->open_stateid.data, stateid->data, sizeof(state->open_stateid.data)); | 452 | memcpy(state->open_stateid.data, stateid->data, sizeof(state->open_stateid.data)); |
| 372 | switch (open_flags) { | 453 | switch (fmode) { |
| 373 | case FMODE_READ: | 454 | case FMODE_READ: |
| 374 | set_bit(NFS_O_RDONLY_STATE, &state->flags); | 455 | set_bit(NFS_O_RDONLY_STATE, &state->flags); |
| 375 | break; | 456 | break; |
| @@ -381,16 +462,15 @@ static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid * | |||
| 381 | } | 462 | } |
| 382 | } | 463 | } |
| 383 | 464 | ||
| 384 | static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) | 465 | static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode) |
| 385 | { | 466 | { |
| 386 | write_seqlock(&state->seqlock); | 467 | write_seqlock(&state->seqlock); |
| 387 | nfs_set_open_stateid_locked(state, stateid, open_flags); | 468 | nfs_set_open_stateid_locked(state, stateid, fmode); |
| 388 | write_sequnlock(&state->seqlock); | 469 | write_sequnlock(&state->seqlock); |
| 389 | } | 470 | } |
| 390 | 471 | ||
| 391 | static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, nfs4_stateid *deleg_stateid, int open_flags) | 472 | static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, const nfs4_stateid *deleg_stateid, fmode_t fmode) |
| 392 | { | 473 | { |
| 393 | open_flags &= (FMODE_READ|FMODE_WRITE); | ||
| 394 | /* | 474 | /* |
| 395 | * Protect the call to nfs4_state_set_mode_locked and | 475 | * Protect the call to nfs4_state_set_mode_locked and |
| 396 | * serialise the stateid update | 476 | * serialise the stateid update |
| @@ -401,20 +481,60 @@ static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_sta | |||
| 401 | set_bit(NFS_DELEGATED_STATE, &state->flags); | 481 | set_bit(NFS_DELEGATED_STATE, &state->flags); |
| 402 | } | 482 | } |
| 403 | if (open_stateid != NULL) | 483 | if (open_stateid != NULL) |
| 404 | nfs_set_open_stateid_locked(state, open_stateid, open_flags); | 484 | nfs_set_open_stateid_locked(state, open_stateid, fmode); |
| 405 | write_sequnlock(&state->seqlock); | 485 | write_sequnlock(&state->seqlock); |
| 406 | spin_lock(&state->owner->so_lock); | 486 | spin_lock(&state->owner->so_lock); |
| 407 | update_open_stateflags(state, open_flags); | 487 | update_open_stateflags(state, fmode); |
| 408 | spin_unlock(&state->owner->so_lock); | 488 | spin_unlock(&state->owner->so_lock); |
| 409 | } | 489 | } |
| 410 | 490 | ||
| 411 | static void nfs4_return_incompatible_delegation(struct inode *inode, mode_t open_flags) | 491 | static int update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, nfs4_stateid *delegation, fmode_t fmode) |
| 492 | { | ||
| 493 | struct nfs_inode *nfsi = NFS_I(state->inode); | ||
| 494 | struct nfs_delegation *deleg_cur; | ||
| 495 | int ret = 0; | ||
| 496 | |||
| 497 | fmode &= (FMODE_READ|FMODE_WRITE); | ||
| 498 | |||
| 499 | rcu_read_lock(); | ||
| 500 | deleg_cur = rcu_dereference(nfsi->delegation); | ||
| 501 | if (deleg_cur == NULL) | ||
| 502 | goto no_delegation; | ||
| 503 | |||
| 504 | spin_lock(&deleg_cur->lock); | ||
| 505 | if (nfsi->delegation != deleg_cur || | ||
| 506 | (deleg_cur->type & fmode) != fmode) | ||
| 507 | goto no_delegation_unlock; | ||
| 508 | |||
| 509 | if (delegation == NULL) | ||
| 510 | delegation = &deleg_cur->stateid; | ||
| 511 | else if (memcmp(deleg_cur->stateid.data, delegation->data, NFS4_STATEID_SIZE) != 0) | ||
| 512 | goto no_delegation_unlock; | ||
| 513 | |||
| 514 | nfs_mark_delegation_referenced(deleg_cur); | ||
| 515 | __update_open_stateid(state, open_stateid, &deleg_cur->stateid, fmode); | ||
| 516 | ret = 1; | ||
| 517 | no_delegation_unlock: | ||
| 518 | spin_unlock(&deleg_cur->lock); | ||
| 519 | no_delegation: | ||
| 520 | rcu_read_unlock(); | ||
| 521 | |||
| 522 | if (!ret && open_stateid != NULL) { | ||
| 523 | __update_open_stateid(state, open_stateid, NULL, fmode); | ||
| 524 | ret = 1; | ||
| 525 | } | ||
| 526 | |||
| 527 | return ret; | ||
| 528 | } | ||
| 529 | |||
| 530 | |||
| 531 | static void nfs4_return_incompatible_delegation(struct inode *inode, fmode_t fmode) | ||
| 412 | { | 532 | { |
| 413 | struct nfs_delegation *delegation; | 533 | struct nfs_delegation *delegation; |
| 414 | 534 | ||
| 415 | rcu_read_lock(); | 535 | rcu_read_lock(); |
| 416 | delegation = rcu_dereference(NFS_I(inode)->delegation); | 536 | delegation = rcu_dereference(NFS_I(inode)->delegation); |
| 417 | if (delegation == NULL || (delegation->type & open_flags) == open_flags) { | 537 | if (delegation == NULL || (delegation->type & fmode) == fmode) { |
| 418 | rcu_read_unlock(); | 538 | rcu_read_unlock(); |
| 419 | return; | 539 | return; |
| 420 | } | 540 | } |
| @@ -427,27 +547,28 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) | |||
| 427 | struct nfs4_state *state = opendata->state; | 547 | struct nfs4_state *state = opendata->state; |
| 428 | struct nfs_inode *nfsi = NFS_I(state->inode); | 548 | struct nfs_inode *nfsi = NFS_I(state->inode); |
| 429 | struct nfs_delegation *delegation; | 549 | struct nfs_delegation *delegation; |
| 430 | int open_mode = opendata->o_arg.open_flags & (FMODE_READ|FMODE_WRITE|O_EXCL); | 550 | int open_mode = opendata->o_arg.open_flags & O_EXCL; |
| 551 | fmode_t fmode = opendata->o_arg.fmode; | ||
| 431 | nfs4_stateid stateid; | 552 | nfs4_stateid stateid; |
| 432 | int ret = -EAGAIN; | 553 | int ret = -EAGAIN; |
| 433 | 554 | ||
| 434 | rcu_read_lock(); | ||
| 435 | delegation = rcu_dereference(nfsi->delegation); | ||
| 436 | for (;;) { | 555 | for (;;) { |
| 437 | if (can_open_cached(state, open_mode)) { | 556 | if (can_open_cached(state, fmode, open_mode)) { |
| 438 | spin_lock(&state->owner->so_lock); | 557 | spin_lock(&state->owner->so_lock); |
| 439 | if (can_open_cached(state, open_mode)) { | 558 | if (can_open_cached(state, fmode, open_mode)) { |
| 440 | update_open_stateflags(state, open_mode); | 559 | update_open_stateflags(state, fmode); |
| 441 | spin_unlock(&state->owner->so_lock); | 560 | spin_unlock(&state->owner->so_lock); |
| 442 | rcu_read_unlock(); | ||
| 443 | goto out_return_state; | 561 | goto out_return_state; |
| 444 | } | 562 | } |
| 445 | spin_unlock(&state->owner->so_lock); | 563 | spin_unlock(&state->owner->so_lock); |
| 446 | } | 564 | } |
| 447 | if (delegation == NULL) | 565 | rcu_read_lock(); |
| 448 | break; | 566 | delegation = rcu_dereference(nfsi->delegation); |
| 449 | if (!can_open_delegated(delegation, open_mode)) | 567 | if (delegation == NULL || |
| 568 | !can_open_delegated(delegation, fmode)) { | ||
| 569 | rcu_read_unlock(); | ||
| 450 | break; | 570 | break; |
| 571 | } | ||
| 451 | /* Save the delegation */ | 572 | /* Save the delegation */ |
| 452 | memcpy(stateid.data, delegation->stateid.data, sizeof(stateid.data)); | 573 | memcpy(stateid.data, delegation->stateid.data, sizeof(stateid.data)); |
| 453 | rcu_read_unlock(); | 574 | rcu_read_unlock(); |
| @@ -455,19 +576,11 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) | |||
| 455 | if (ret != 0) | 576 | if (ret != 0) |
| 456 | goto out; | 577 | goto out; |
| 457 | ret = -EAGAIN; | 578 | ret = -EAGAIN; |
| 458 | rcu_read_lock(); | 579 | |
| 459 | delegation = rcu_dereference(nfsi->delegation); | 580 | /* Try to update the stateid using the delegation */ |
| 460 | /* If no delegation, try a cached open */ | 581 | if (update_open_stateid(state, NULL, &stateid, fmode)) |
| 461 | if (delegation == NULL) | 582 | goto out_return_state; |
| 462 | continue; | ||
| 463 | /* Is the delegation still valid? */ | ||
| 464 | if (memcmp(stateid.data, delegation->stateid.data, sizeof(stateid.data)) != 0) | ||
| 465 | continue; | ||
| 466 | rcu_read_unlock(); | ||
| 467 | update_open_stateid(state, NULL, &stateid, open_mode); | ||
| 468 | goto out_return_state; | ||
| 469 | } | 583 | } |
| 470 | rcu_read_unlock(); | ||
| 471 | out: | 584 | out: |
| 472 | return ERR_PTR(ret); | 585 | return ERR_PTR(ret); |
| 473 | out_return_state: | 586 | out_return_state: |
| @@ -480,7 +593,6 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data | |||
| 480 | struct inode *inode; | 593 | struct inode *inode; |
| 481 | struct nfs4_state *state = NULL; | 594 | struct nfs4_state *state = NULL; |
| 482 | struct nfs_delegation *delegation; | 595 | struct nfs_delegation *delegation; |
| 483 | nfs4_stateid *deleg_stateid = NULL; | ||
| 484 | int ret; | 596 | int ret; |
| 485 | 597 | ||
| 486 | if (!data->rpc_done) { | 598 | if (!data->rpc_done) { |
| @@ -507,7 +619,7 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data | |||
| 507 | if (delegation) | 619 | if (delegation) |
| 508 | delegation_flags = delegation->flags; | 620 | delegation_flags = delegation->flags; |
| 509 | rcu_read_unlock(); | 621 | rcu_read_unlock(); |
| 510 | if (!(delegation_flags & NFS_DELEGATION_NEED_RECLAIM)) | 622 | if ((delegation_flags & 1UL<<NFS_DELEGATION_NEED_RECLAIM) == 0) |
| 511 | nfs_inode_set_delegation(state->inode, | 623 | nfs_inode_set_delegation(state->inode, |
| 512 | data->owner->so_cred, | 624 | data->owner->so_cred, |
| 513 | &data->o_res); | 625 | &data->o_res); |
| @@ -516,12 +628,9 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data | |||
| 516 | data->owner->so_cred, | 628 | data->owner->so_cred, |
| 517 | &data->o_res); | 629 | &data->o_res); |
| 518 | } | 630 | } |
| 519 | rcu_read_lock(); | 631 | |
| 520 | delegation = rcu_dereference(NFS_I(inode)->delegation); | 632 | update_open_stateid(state, &data->o_res.stateid, NULL, |
| 521 | if (delegation != NULL) | 633 | data->o_arg.fmode); |
| 522 | deleg_stateid = &delegation->stateid; | ||
| 523 | update_open_stateid(state, &data->o_res.stateid, deleg_stateid, data->o_arg.open_flags); | ||
| 524 | rcu_read_unlock(); | ||
| 525 | iput(inode); | 634 | iput(inode); |
| 526 | out: | 635 | out: |
| 527 | return state; | 636 | return state; |
| @@ -552,7 +661,7 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context | |||
| 552 | { | 661 | { |
| 553 | struct nfs4_opendata *opendata; | 662 | struct nfs4_opendata *opendata; |
| 554 | 663 | ||
| 555 | opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL); | 664 | opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, 0, NULL); |
| 556 | if (opendata == NULL) | 665 | if (opendata == NULL) |
| 557 | return ERR_PTR(-ENOMEM); | 666 | return ERR_PTR(-ENOMEM); |
| 558 | opendata->state = state; | 667 | opendata->state = state; |
| @@ -560,12 +669,13 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context | |||
| 560 | return opendata; | 669 | return opendata; |
| 561 | } | 670 | } |
| 562 | 671 | ||
| 563 | static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, struct nfs4_state **res) | 672 | static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, fmode_t fmode, struct nfs4_state **res) |
| 564 | { | 673 | { |
| 565 | struct nfs4_state *newstate; | 674 | struct nfs4_state *newstate; |
| 566 | int ret; | 675 | int ret; |
| 567 | 676 | ||
| 568 | opendata->o_arg.open_flags = openflags; | 677 | opendata->o_arg.open_flags = 0; |
| 678 | opendata->o_arg.fmode = fmode; | ||
| 569 | memset(&opendata->o_res, 0, sizeof(opendata->o_res)); | 679 | memset(&opendata->o_res, 0, sizeof(opendata->o_res)); |
| 570 | memset(&opendata->c_res, 0, sizeof(opendata->c_res)); | 680 | memset(&opendata->c_res, 0, sizeof(opendata->c_res)); |
| 571 | nfs4_init_opendata_res(opendata); | 681 | nfs4_init_opendata_res(opendata); |
| @@ -575,7 +685,7 @@ static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openf | |||
| 575 | newstate = nfs4_opendata_to_nfs4_state(opendata); | 685 | newstate = nfs4_opendata_to_nfs4_state(opendata); |
| 576 | if (IS_ERR(newstate)) | 686 | if (IS_ERR(newstate)) |
| 577 | return PTR_ERR(newstate); | 687 | return PTR_ERR(newstate); |
| 578 | nfs4_close_state(&opendata->path, newstate, openflags); | 688 | nfs4_close_state(&opendata->path, newstate, fmode); |
| 579 | *res = newstate; | 689 | *res = newstate; |
| 580 | return 0; | 690 | return 0; |
| 581 | } | 691 | } |
| @@ -631,7 +741,7 @@ static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state | |||
| 631 | { | 741 | { |
| 632 | struct nfs_delegation *delegation; | 742 | struct nfs_delegation *delegation; |
| 633 | struct nfs4_opendata *opendata; | 743 | struct nfs4_opendata *opendata; |
| 634 | int delegation_type = 0; | 744 | fmode_t delegation_type = 0; |
| 635 | int status; | 745 | int status; |
| 636 | 746 | ||
| 637 | opendata = nfs4_open_recoverdata_alloc(ctx, state); | 747 | opendata = nfs4_open_recoverdata_alloc(ctx, state); |
| @@ -641,7 +751,7 @@ static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state | |||
| 641 | opendata->o_arg.fh = NFS_FH(state->inode); | 751 | opendata->o_arg.fh = NFS_FH(state->inode); |
| 642 | rcu_read_lock(); | 752 | rcu_read_lock(); |
| 643 | delegation = rcu_dereference(NFS_I(state->inode)->delegation); | 753 | delegation = rcu_dereference(NFS_I(state->inode)->delegation); |
| 644 | if (delegation != NULL && (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) != 0) | 754 | if (delegation != NULL && test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags) != 0) |
| 645 | delegation_type = delegation->type; | 755 | delegation_type = delegation->type; |
| 646 | rcu_read_unlock(); | 756 | rcu_read_unlock(); |
| 647 | opendata->o_arg.u.delegation_type = delegation_type; | 757 | opendata->o_arg.u.delegation_type = delegation_type; |
| @@ -744,7 +854,7 @@ static void nfs4_open_confirm_release(void *calldata) | |||
| 744 | goto out_free; | 854 | goto out_free; |
| 745 | state = nfs4_opendata_to_nfs4_state(data); | 855 | state = nfs4_opendata_to_nfs4_state(data); |
| 746 | if (!IS_ERR(state)) | 856 | if (!IS_ERR(state)) |
| 747 | nfs4_close_state(&data->path, state, data->o_arg.open_flags); | 857 | nfs4_close_state(&data->path, state, data->o_arg.fmode); |
| 748 | out_free: | 858 | out_free: |
| 749 | nfs4_opendata_put(data); | 859 | nfs4_opendata_put(data); |
| 750 | } | 860 | } |
| @@ -808,12 +918,12 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) | |||
| 808 | if (data->state != NULL) { | 918 | if (data->state != NULL) { |
| 809 | struct nfs_delegation *delegation; | 919 | struct nfs_delegation *delegation; |
| 810 | 920 | ||
| 811 | if (can_open_cached(data->state, data->o_arg.open_flags & (FMODE_READ|FMODE_WRITE|O_EXCL))) | 921 | if (can_open_cached(data->state, data->o_arg.fmode, data->o_arg.open_flags)) |
| 812 | goto out_no_action; | 922 | goto out_no_action; |
| 813 | rcu_read_lock(); | 923 | rcu_read_lock(); |
| 814 | delegation = rcu_dereference(NFS_I(data->state->inode)->delegation); | 924 | delegation = rcu_dereference(NFS_I(data->state->inode)->delegation); |
| 815 | if (delegation != NULL && | 925 | if (delegation != NULL && |
| 816 | (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) == 0) { | 926 | test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags) == 0) { |
| 817 | rcu_read_unlock(); | 927 | rcu_read_unlock(); |
| 818 | goto out_no_action; | 928 | goto out_no_action; |
| 819 | } | 929 | } |
| @@ -877,7 +987,7 @@ static void nfs4_open_release(void *calldata) | |||
| 877 | goto out_free; | 987 | goto out_free; |
| 878 | state = nfs4_opendata_to_nfs4_state(data); | 988 | state = nfs4_opendata_to_nfs4_state(data); |
| 879 | if (!IS_ERR(state)) | 989 | if (!IS_ERR(state)) |
| 880 | nfs4_close_state(&data->path, state, data->o_arg.open_flags); | 990 | nfs4_close_state(&data->path, state, data->o_arg.fmode); |
| 881 | out_free: | 991 | out_free: |
| 882 | nfs4_opendata_put(data); | 992 | nfs4_opendata_put(data); |
| 883 | } | 993 | } |
| @@ -955,10 +1065,11 @@ static int nfs4_recover_expired_lease(struct nfs_server *server) | |||
| 955 | int ret; | 1065 | int ret; |
| 956 | 1066 | ||
| 957 | for (;;) { | 1067 | for (;;) { |
| 958 | ret = nfs4_wait_clnt_recover(server->client, clp); | 1068 | ret = nfs4_wait_clnt_recover(clp); |
| 959 | if (ret != 0) | 1069 | if (ret != 0) |
| 960 | return ret; | 1070 | return ret; |
| 961 | if (!test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) | 1071 | if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) && |
| 1072 | !test_bit(NFS4CLNT_CHECK_LEASE,&clp->cl_state)) | ||
| 962 | break; | 1073 | break; |
| 963 | nfs4_schedule_state_recovery(clp); | 1074 | nfs4_schedule_state_recovery(clp); |
| 964 | } | 1075 | } |
| @@ -993,8 +1104,9 @@ static inline int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4 | |||
| 993 | 1104 | ||
| 994 | do { | 1105 | do { |
| 995 | err = _nfs4_open_expired(ctx, state); | 1106 | err = _nfs4_open_expired(ctx, state); |
| 996 | if (err == -NFS4ERR_DELAY) | 1107 | if (err != -NFS4ERR_DELAY) |
| 997 | nfs4_handle_exception(server, err, &exception); | 1108 | break; |
| 1109 | nfs4_handle_exception(server, err, &exception); | ||
| 998 | } while (exception.retry); | 1110 | } while (exception.retry); |
| 999 | return err; | 1111 | return err; |
| 1000 | } | 1112 | } |
| @@ -1031,12 +1143,11 @@ static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata, struct | |||
| 1031 | /* | 1143 | /* |
| 1032 | * Returns a referenced nfs4_state | 1144 | * Returns a referenced nfs4_state |
| 1033 | */ | 1145 | */ |
| 1034 | static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) | 1146 | static int _nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) |
| 1035 | { | 1147 | { |
| 1036 | struct nfs4_state_owner *sp; | 1148 | struct nfs4_state_owner *sp; |
| 1037 | struct nfs4_state *state = NULL; | 1149 | struct nfs4_state *state = NULL; |
| 1038 | struct nfs_server *server = NFS_SERVER(dir); | 1150 | struct nfs_server *server = NFS_SERVER(dir); |
| 1039 | struct nfs_client *clp = server->nfs_client; | ||
| 1040 | struct nfs4_opendata *opendata; | 1151 | struct nfs4_opendata *opendata; |
| 1041 | int status; | 1152 | int status; |
| 1042 | 1153 | ||
| @@ -1050,12 +1161,11 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct | |||
| 1050 | if (status != 0) | 1161 | if (status != 0) |
| 1051 | goto err_put_state_owner; | 1162 | goto err_put_state_owner; |
| 1052 | if (path->dentry->d_inode != NULL) | 1163 | if (path->dentry->d_inode != NULL) |
| 1053 | nfs4_return_incompatible_delegation(path->dentry->d_inode, flags & (FMODE_READ|FMODE_WRITE)); | 1164 | nfs4_return_incompatible_delegation(path->dentry->d_inode, fmode); |
| 1054 | down_read(&clp->cl_sem); | ||
| 1055 | status = -ENOMEM; | 1165 | status = -ENOMEM; |
| 1056 | opendata = nfs4_opendata_alloc(path, sp, flags, sattr); | 1166 | opendata = nfs4_opendata_alloc(path, sp, fmode, flags, sattr); |
| 1057 | if (opendata == NULL) | 1167 | if (opendata == NULL) |
| 1058 | goto err_release_rwsem; | 1168 | goto err_put_state_owner; |
| 1059 | 1169 | ||
| 1060 | if (path->dentry->d_inode != NULL) | 1170 | if (path->dentry->d_inode != NULL) |
| 1061 | opendata->state = nfs4_get_open_state(path->dentry->d_inode, sp); | 1171 | opendata->state = nfs4_get_open_state(path->dentry->d_inode, sp); |
| @@ -1073,13 +1183,10 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct | |||
| 1073 | goto err_opendata_put; | 1183 | goto err_opendata_put; |
| 1074 | nfs4_opendata_put(opendata); | 1184 | nfs4_opendata_put(opendata); |
| 1075 | nfs4_put_state_owner(sp); | 1185 | nfs4_put_state_owner(sp); |
| 1076 | up_read(&clp->cl_sem); | ||
| 1077 | *res = state; | 1186 | *res = state; |
| 1078 | return 0; | 1187 | return 0; |
| 1079 | err_opendata_put: | 1188 | err_opendata_put: |
| 1080 | nfs4_opendata_put(opendata); | 1189 | nfs4_opendata_put(opendata); |
| 1081 | err_release_rwsem: | ||
| 1082 | up_read(&clp->cl_sem); | ||
| 1083 | err_put_state_owner: | 1190 | err_put_state_owner: |
| 1084 | nfs4_put_state_owner(sp); | 1191 | nfs4_put_state_owner(sp); |
| 1085 | out_err: | 1192 | out_err: |
| @@ -1088,14 +1195,14 @@ out_err: | |||
| 1088 | } | 1195 | } |
| 1089 | 1196 | ||
| 1090 | 1197 | ||
| 1091 | static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred) | 1198 | static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, int flags, struct iattr *sattr, struct rpc_cred *cred) |
| 1092 | { | 1199 | { |
| 1093 | struct nfs4_exception exception = { }; | 1200 | struct nfs4_exception exception = { }; |
| 1094 | struct nfs4_state *res; | 1201 | struct nfs4_state *res; |
| 1095 | int status; | 1202 | int status; |
| 1096 | 1203 | ||
| 1097 | do { | 1204 | do { |
| 1098 | status = _nfs4_do_open(dir, path, flags, sattr, cred, &res); | 1205 | status = _nfs4_do_open(dir, path, fmode, flags, sattr, cred, &res); |
| 1099 | if (status == 0) | 1206 | if (status == 0) |
| 1100 | break; | 1207 | break; |
| 1101 | /* NOTE: BAD_SEQID means the server and client disagree about the | 1208 | /* NOTE: BAD_SEQID means the server and client disagree about the |
| @@ -1230,10 +1337,13 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
| 1230 | renew_lease(server, calldata->timestamp); | 1337 | renew_lease(server, calldata->timestamp); |
| 1231 | break; | 1338 | break; |
| 1232 | case -NFS4ERR_STALE_STATEID: | 1339 | case -NFS4ERR_STALE_STATEID: |
| 1340 | case -NFS4ERR_OLD_STATEID: | ||
| 1341 | case -NFS4ERR_BAD_STATEID: | ||
| 1233 | case -NFS4ERR_EXPIRED: | 1342 | case -NFS4ERR_EXPIRED: |
| 1234 | break; | 1343 | if (calldata->arg.fmode == 0) |
| 1344 | break; | ||
| 1235 | default: | 1345 | default: |
| 1236 | if (nfs4_async_handle_error(task, server) == -EAGAIN) { | 1346 | if (nfs4_async_handle_error(task, server, state) == -EAGAIN) { |
| 1237 | rpc_restart_call(task); | 1347 | rpc_restart_call(task); |
| 1238 | return; | 1348 | return; |
| 1239 | } | 1349 | } |
| @@ -1272,10 +1382,10 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
| 1272 | nfs_fattr_init(calldata->res.fattr); | 1382 | nfs_fattr_init(calldata->res.fattr); |
| 1273 | if (test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0) { | 1383 | if (test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0) { |
| 1274 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; | 1384 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; |
| 1275 | calldata->arg.open_flags = FMODE_READ; | 1385 | calldata->arg.fmode = FMODE_READ; |
| 1276 | } else if (test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0) { | 1386 | } else if (test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0) { |
| 1277 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; | 1387 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; |
| 1278 | calldata->arg.open_flags = FMODE_WRITE; | 1388 | calldata->arg.fmode = FMODE_WRITE; |
| 1279 | } | 1389 | } |
| 1280 | calldata->timestamp = jiffies; | 1390 | calldata->timestamp = jiffies; |
| 1281 | rpc_call_start(task); | 1391 | rpc_call_start(task); |
| @@ -1328,6 +1438,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
| 1328 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); | 1438 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); |
| 1329 | if (calldata->arg.seqid == NULL) | 1439 | if (calldata->arg.seqid == NULL) |
| 1330 | goto out_free_calldata; | 1440 | goto out_free_calldata; |
| 1441 | calldata->arg.fmode = 0; | ||
| 1331 | calldata->arg.bitmask = server->attr_bitmask; | 1442 | calldata->arg.bitmask = server->attr_bitmask; |
| 1332 | calldata->res.fattr = &calldata->fattr; | 1443 | calldata->res.fattr = &calldata->fattr; |
| 1333 | calldata->res.seqid = calldata->arg.seqid; | 1444 | calldata->res.seqid = calldata->arg.seqid; |
| @@ -1354,13 +1465,13 @@ out: | |||
| 1354 | return status; | 1465 | return status; |
| 1355 | } | 1466 | } |
| 1356 | 1467 | ||
| 1357 | static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct nfs4_state *state) | 1468 | static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct nfs4_state *state, fmode_t fmode) |
| 1358 | { | 1469 | { |
| 1359 | struct file *filp; | 1470 | struct file *filp; |
| 1360 | int ret; | 1471 | int ret; |
| 1361 | 1472 | ||
| 1362 | /* If the open_intent is for execute, we have an extra check to make */ | 1473 | /* If the open_intent is for execute, we have an extra check to make */ |
| 1363 | if (nd->intent.open.flags & FMODE_EXEC) { | 1474 | if (fmode & FMODE_EXEC) { |
| 1364 | ret = nfs_may_open(state->inode, | 1475 | ret = nfs_may_open(state->inode, |
| 1365 | state->owner->so_cred, | 1476 | state->owner->so_cred, |
| 1366 | nd->intent.open.flags); | 1477 | nd->intent.open.flags); |
| @@ -1376,7 +1487,7 @@ static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct | |||
| 1376 | } | 1487 | } |
| 1377 | ret = PTR_ERR(filp); | 1488 | ret = PTR_ERR(filp); |
| 1378 | out_close: | 1489 | out_close: |
| 1379 | nfs4_close_sync(path, state, nd->intent.open.flags); | 1490 | nfs4_close_sync(path, state, fmode & (FMODE_READ|FMODE_WRITE)); |
| 1380 | return ret; | 1491 | return ret; |
| 1381 | } | 1492 | } |
| 1382 | 1493 | ||
| @@ -1392,6 +1503,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |||
| 1392 | struct rpc_cred *cred; | 1503 | struct rpc_cred *cred; |
| 1393 | struct nfs4_state *state; | 1504 | struct nfs4_state *state; |
| 1394 | struct dentry *res; | 1505 | struct dentry *res; |
| 1506 | fmode_t fmode = nd->intent.open.flags & (FMODE_READ | FMODE_WRITE | FMODE_EXEC); | ||
| 1395 | 1507 | ||
| 1396 | if (nd->flags & LOOKUP_CREATE) { | 1508 | if (nd->flags & LOOKUP_CREATE) { |
| 1397 | attr.ia_mode = nd->intent.open.create_mode; | 1509 | attr.ia_mode = nd->intent.open.create_mode; |
| @@ -1409,7 +1521,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |||
| 1409 | parent = dentry->d_parent; | 1521 | parent = dentry->d_parent; |
| 1410 | /* Protect against concurrent sillydeletes */ | 1522 | /* Protect against concurrent sillydeletes */ |
| 1411 | nfs_block_sillyrename(parent); | 1523 | nfs_block_sillyrename(parent); |
| 1412 | state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred); | 1524 | state = nfs4_do_open(dir, &path, fmode, nd->intent.open.flags, &attr, cred); |
| 1413 | put_rpccred(cred); | 1525 | put_rpccred(cred); |
| 1414 | if (IS_ERR(state)) { | 1526 | if (IS_ERR(state)) { |
| 1415 | if (PTR_ERR(state) == -ENOENT) { | 1527 | if (PTR_ERR(state) == -ENOENT) { |
| @@ -1424,7 +1536,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |||
| 1424 | path.dentry = res; | 1536 | path.dentry = res; |
| 1425 | nfs_set_verifier(path.dentry, nfs_save_change_attribute(dir)); | 1537 | nfs_set_verifier(path.dentry, nfs_save_change_attribute(dir)); |
| 1426 | nfs_unblock_sillyrename(parent); | 1538 | nfs_unblock_sillyrename(parent); |
| 1427 | nfs4_intent_set_file(nd, &path, state); | 1539 | nfs4_intent_set_file(nd, &path, state, fmode); |
| 1428 | return res; | 1540 | return res; |
| 1429 | } | 1541 | } |
| 1430 | 1542 | ||
| @@ -1437,11 +1549,12 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st | |||
| 1437 | }; | 1549 | }; |
| 1438 | struct rpc_cred *cred; | 1550 | struct rpc_cred *cred; |
| 1439 | struct nfs4_state *state; | 1551 | struct nfs4_state *state; |
| 1552 | fmode_t fmode = openflags & (FMODE_READ | FMODE_WRITE); | ||
| 1440 | 1553 | ||
| 1441 | cred = rpc_lookup_cred(); | 1554 | cred = rpc_lookup_cred(); |
| 1442 | if (IS_ERR(cred)) | 1555 | if (IS_ERR(cred)) |
| 1443 | return PTR_ERR(cred); | 1556 | return PTR_ERR(cred); |
| 1444 | state = nfs4_do_open(dir, &path, openflags, NULL, cred); | 1557 | state = nfs4_do_open(dir, &path, fmode, openflags, NULL, cred); |
| 1445 | put_rpccred(cred); | 1558 | put_rpccred(cred); |
| 1446 | if (IS_ERR(state)) { | 1559 | if (IS_ERR(state)) { |
| 1447 | switch (PTR_ERR(state)) { | 1560 | switch (PTR_ERR(state)) { |
| @@ -1458,10 +1571,10 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st | |||
| 1458 | } | 1571 | } |
| 1459 | if (state->inode == dentry->d_inode) { | 1572 | if (state->inode == dentry->d_inode) { |
| 1460 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | 1573 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
| 1461 | nfs4_intent_set_file(nd, &path, state); | 1574 | nfs4_intent_set_file(nd, &path, state, fmode); |
| 1462 | return 1; | 1575 | return 1; |
| 1463 | } | 1576 | } |
| 1464 | nfs4_close_sync(&path, state, openflags); | 1577 | nfs4_close_sync(&path, state, fmode); |
| 1465 | out_drop: | 1578 | out_drop: |
| 1466 | d_drop(dentry); | 1579 | d_drop(dentry); |
| 1467 | return 0; | 1580 | return 0; |
| @@ -1887,6 +2000,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
| 1887 | }; | 2000 | }; |
| 1888 | struct nfs4_state *state; | 2001 | struct nfs4_state *state; |
| 1889 | struct rpc_cred *cred; | 2002 | struct rpc_cred *cred; |
| 2003 | fmode_t fmode = flags & (FMODE_READ | FMODE_WRITE); | ||
| 1890 | int status = 0; | 2004 | int status = 0; |
| 1891 | 2005 | ||
| 1892 | cred = rpc_lookup_cred(); | 2006 | cred = rpc_lookup_cred(); |
| @@ -1894,7 +2008,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
| 1894 | status = PTR_ERR(cred); | 2008 | status = PTR_ERR(cred); |
| 1895 | goto out; | 2009 | goto out; |
| 1896 | } | 2010 | } |
| 1897 | state = nfs4_do_open(dir, &path, flags, sattr, cred); | 2011 | state = nfs4_do_open(dir, &path, fmode, flags, sattr, cred); |
| 1898 | d_drop(dentry); | 2012 | d_drop(dentry); |
| 1899 | if (IS_ERR(state)) { | 2013 | if (IS_ERR(state)) { |
| 1900 | status = PTR_ERR(state); | 2014 | status = PTR_ERR(state); |
| @@ -1910,9 +2024,9 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
| 1910 | nfs_post_op_update_inode(state->inode, &fattr); | 2024 | nfs_post_op_update_inode(state->inode, &fattr); |
| 1911 | } | 2025 | } |
| 1912 | if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0) | 2026 | if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0) |
| 1913 | status = nfs4_intent_set_file(nd, &path, state); | 2027 | status = nfs4_intent_set_file(nd, &path, state, fmode); |
| 1914 | else | 2028 | else |
| 1915 | nfs4_close_sync(&path, state, flags); | 2029 | nfs4_close_sync(&path, state, fmode); |
| 1916 | out_putcred: | 2030 | out_putcred: |
| 1917 | put_rpccred(cred); | 2031 | put_rpccred(cred); |
| 1918 | out: | 2032 | out: |
| @@ -1974,7 +2088,7 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir) | |||
| 1974 | { | 2088 | { |
| 1975 | struct nfs_removeres *res = task->tk_msg.rpc_resp; | 2089 | struct nfs_removeres *res = task->tk_msg.rpc_resp; |
| 1976 | 2090 | ||
| 1977 | if (nfs4_async_handle_error(task, res->server) == -EAGAIN) | 2091 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) |
| 1978 | return 0; | 2092 | return 0; |
| 1979 | update_changeattr(dir, &res->cinfo); | 2093 | update_changeattr(dir, &res->cinfo); |
| 1980 | nfs_post_op_update_inode(dir, &res->dir_attr); | 2094 | nfs_post_op_update_inode(dir, &res->dir_attr); |
| @@ -2402,7 +2516,7 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) | |||
| 2402 | { | 2516 | { |
| 2403 | struct nfs_server *server = NFS_SERVER(data->inode); | 2517 | struct nfs_server *server = NFS_SERVER(data->inode); |
| 2404 | 2518 | ||
| 2405 | if (nfs4_async_handle_error(task, server) == -EAGAIN) { | 2519 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { |
| 2406 | rpc_restart_call(task); | 2520 | rpc_restart_call(task); |
| 2407 | return -EAGAIN; | 2521 | return -EAGAIN; |
| 2408 | } | 2522 | } |
| @@ -2423,7 +2537,7 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) | |||
| 2423 | { | 2537 | { |
| 2424 | struct inode *inode = data->inode; | 2538 | struct inode *inode = data->inode; |
| 2425 | 2539 | ||
| 2426 | if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { | 2540 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { |
| 2427 | rpc_restart_call(task); | 2541 | rpc_restart_call(task); |
| 2428 | return -EAGAIN; | 2542 | return -EAGAIN; |
| 2429 | } | 2543 | } |
| @@ -2449,7 +2563,7 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) | |||
| 2449 | { | 2563 | { |
| 2450 | struct inode *inode = data->inode; | 2564 | struct inode *inode = data->inode; |
| 2451 | 2565 | ||
| 2452 | if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { | 2566 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { |
| 2453 | rpc_restart_call(task); | 2567 | rpc_restart_call(task); |
| 2454 | return -EAGAIN; | 2568 | return -EAGAIN; |
| 2455 | } | 2569 | } |
| @@ -2742,19 +2856,25 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen | |||
| 2742 | } | 2856 | } |
| 2743 | 2857 | ||
| 2744 | static int | 2858 | static int |
| 2745 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server) | 2859 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state) |
| 2746 | { | 2860 | { |
| 2747 | struct nfs_client *clp = server->nfs_client; | 2861 | struct nfs_client *clp = server->nfs_client; |
| 2748 | 2862 | ||
| 2749 | if (!clp || task->tk_status >= 0) | 2863 | if (!clp || task->tk_status >= 0) |
| 2750 | return 0; | 2864 | return 0; |
| 2751 | switch(task->tk_status) { | 2865 | switch(task->tk_status) { |
| 2866 | case -NFS4ERR_ADMIN_REVOKED: | ||
| 2867 | case -NFS4ERR_BAD_STATEID: | ||
| 2868 | case -NFS4ERR_OPENMODE: | ||
| 2869 | if (state == NULL) | ||
| 2870 | break; | ||
| 2871 | nfs4_state_mark_reclaim_nograce(clp, state); | ||
| 2752 | case -NFS4ERR_STALE_CLIENTID: | 2872 | case -NFS4ERR_STALE_CLIENTID: |
| 2753 | case -NFS4ERR_STALE_STATEID: | 2873 | case -NFS4ERR_STALE_STATEID: |
| 2754 | case -NFS4ERR_EXPIRED: | 2874 | case -NFS4ERR_EXPIRED: |
| 2755 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL); | 2875 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL); |
| 2756 | nfs4_schedule_state_recovery(clp); | 2876 | nfs4_schedule_state_recovery(clp); |
| 2757 | if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) == 0) | 2877 | if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0) |
| 2758 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); | 2878 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); |
| 2759 | task->tk_status = 0; | 2879 | task->tk_status = 0; |
| 2760 | return -EAGAIN; | 2880 | return -EAGAIN; |
| @@ -2772,79 +2892,6 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server) | |||
| 2772 | return 0; | 2892 | return 0; |
| 2773 | } | 2893 | } |
| 2774 | 2894 | ||
| 2775 | static int nfs4_wait_bit_killable(void *word) | ||
| 2776 | { | ||
| 2777 | if (fatal_signal_pending(current)) | ||
| 2778 | return -ERESTARTSYS; | ||
| 2779 | schedule(); | ||
| 2780 | return 0; | ||
| 2781 | } | ||
| 2782 | |||
| 2783 | static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp) | ||
| 2784 | { | ||
| 2785 | int res; | ||
| 2786 | |||
| 2787 | might_sleep(); | ||
| 2788 | |||
| 2789 | rwsem_acquire(&clp->cl_sem.dep_map, 0, 0, _RET_IP_); | ||
| 2790 | |||
| 2791 | res = wait_on_bit(&clp->cl_state, NFS4CLNT_STATE_RECOVER, | ||
| 2792 | nfs4_wait_bit_killable, TASK_KILLABLE); | ||
| 2793 | |||
| 2794 | rwsem_release(&clp->cl_sem.dep_map, 1, _RET_IP_); | ||
| 2795 | return res; | ||
| 2796 | } | ||
| 2797 | |||
| 2798 | static int nfs4_delay(struct rpc_clnt *clnt, long *timeout) | ||
| 2799 | { | ||
| 2800 | int res = 0; | ||
| 2801 | |||
| 2802 | might_sleep(); | ||
| 2803 | |||
| 2804 | if (*timeout <= 0) | ||
| 2805 | *timeout = NFS4_POLL_RETRY_MIN; | ||
| 2806 | if (*timeout > NFS4_POLL_RETRY_MAX) | ||
| 2807 | *timeout = NFS4_POLL_RETRY_MAX; | ||
| 2808 | schedule_timeout_killable(*timeout); | ||
| 2809 | if (fatal_signal_pending(current)) | ||
| 2810 | res = -ERESTARTSYS; | ||
| 2811 | *timeout <<= 1; | ||
| 2812 | return res; | ||
| 2813 | } | ||
| 2814 | |||
| 2815 | /* This is the error handling routine for processes that are allowed | ||
| 2816 | * to sleep. | ||
| 2817 | */ | ||
| 2818 | static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception) | ||
| 2819 | { | ||
| 2820 | struct nfs_client *clp = server->nfs_client; | ||
| 2821 | int ret = errorcode; | ||
| 2822 | |||
| 2823 | exception->retry = 0; | ||
| 2824 | switch(errorcode) { | ||
| 2825 | case 0: | ||
| 2826 | return 0; | ||
| 2827 | case -NFS4ERR_STALE_CLIENTID: | ||
| 2828 | case -NFS4ERR_STALE_STATEID: | ||
| 2829 | case -NFS4ERR_EXPIRED: | ||
| 2830 | nfs4_schedule_state_recovery(clp); | ||
| 2831 | ret = nfs4_wait_clnt_recover(server->client, clp); | ||
| 2832 | if (ret == 0) | ||
| 2833 | exception->retry = 1; | ||
| 2834 | break; | ||
| 2835 | case -NFS4ERR_FILE_OPEN: | ||
| 2836 | case -NFS4ERR_GRACE: | ||
| 2837 | case -NFS4ERR_DELAY: | ||
| 2838 | ret = nfs4_delay(server->client, &exception->timeout); | ||
| 2839 | if (ret != 0) | ||
| 2840 | break; | ||
| 2841 | case -NFS4ERR_OLD_STATEID: | ||
| 2842 | exception->retry = 1; | ||
| 2843 | } | ||
| 2844 | /* We failed to handle the error */ | ||
| 2845 | return nfs4_map_errors(ret); | ||
| 2846 | } | ||
| 2847 | |||
| 2848 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short port, struct rpc_cred *cred) | 2895 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short port, struct rpc_cred *cred) |
| 2849 | { | 2896 | { |
| 2850 | nfs4_verifier sc_verifier; | 2897 | nfs4_verifier sc_verifier; |
| @@ -2916,7 +2963,6 @@ static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cre | |||
| 2916 | spin_lock(&clp->cl_lock); | 2963 | spin_lock(&clp->cl_lock); |
| 2917 | clp->cl_lease_time = fsinfo.lease_time * HZ; | 2964 | clp->cl_lease_time = fsinfo.lease_time * HZ; |
| 2918 | clp->cl_last_renewal = now; | 2965 | clp->cl_last_renewal = now; |
| 2919 | clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
| 2920 | spin_unlock(&clp->cl_lock); | 2966 | spin_unlock(&clp->cl_lock); |
| 2921 | } | 2967 | } |
| 2922 | return status; | 2968 | return status; |
| @@ -3074,7 +3120,6 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
| 3074 | struct nfs4_lock_state *lsp; | 3120 | struct nfs4_lock_state *lsp; |
| 3075 | int status; | 3121 | int status; |
| 3076 | 3122 | ||
| 3077 | down_read(&clp->cl_sem); | ||
| 3078 | arg.lock_owner.clientid = clp->cl_clientid; | 3123 | arg.lock_owner.clientid = clp->cl_clientid; |
| 3079 | status = nfs4_set_lock_state(state, request); | 3124 | status = nfs4_set_lock_state(state, request); |
| 3080 | if (status != 0) | 3125 | if (status != 0) |
| @@ -3091,7 +3136,6 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
| 3091 | } | 3136 | } |
| 3092 | request->fl_ops->fl_release_private(request); | 3137 | request->fl_ops->fl_release_private(request); |
| 3093 | out: | 3138 | out: |
| 3094 | up_read(&clp->cl_sem); | ||
| 3095 | return status; | 3139 | return status; |
| 3096 | } | 3140 | } |
| 3097 | 3141 | ||
| @@ -3181,11 +3225,13 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
| 3181 | sizeof(calldata->lsp->ls_stateid.data)); | 3225 | sizeof(calldata->lsp->ls_stateid.data)); |
| 3182 | renew_lease(calldata->server, calldata->timestamp); | 3226 | renew_lease(calldata->server, calldata->timestamp); |
| 3183 | break; | 3227 | break; |
| 3228 | case -NFS4ERR_BAD_STATEID: | ||
| 3229 | case -NFS4ERR_OLD_STATEID: | ||
| 3184 | case -NFS4ERR_STALE_STATEID: | 3230 | case -NFS4ERR_STALE_STATEID: |
| 3185 | case -NFS4ERR_EXPIRED: | 3231 | case -NFS4ERR_EXPIRED: |
| 3186 | break; | 3232 | break; |
| 3187 | default: | 3233 | default: |
| 3188 | if (nfs4_async_handle_error(task, calldata->server) == -EAGAIN) | 3234 | if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN) |
| 3189 | rpc_restart_call(task); | 3235 | rpc_restart_call(task); |
| 3190 | } | 3236 | } |
| 3191 | } | 3237 | } |
| @@ -3248,6 +3294,7 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl, | |||
| 3248 | 3294 | ||
| 3249 | static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) | 3295 | static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) |
| 3250 | { | 3296 | { |
| 3297 | struct nfs_inode *nfsi = NFS_I(state->inode); | ||
| 3251 | struct nfs_seqid *seqid; | 3298 | struct nfs_seqid *seqid; |
| 3252 | struct nfs4_lock_state *lsp; | 3299 | struct nfs4_lock_state *lsp; |
| 3253 | struct rpc_task *task; | 3300 | struct rpc_task *task; |
| @@ -3257,8 +3304,12 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * | |||
| 3257 | status = nfs4_set_lock_state(state, request); | 3304 | status = nfs4_set_lock_state(state, request); |
| 3258 | /* Unlock _before_ we do the RPC call */ | 3305 | /* Unlock _before_ we do the RPC call */ |
| 3259 | request->fl_flags |= FL_EXISTS; | 3306 | request->fl_flags |= FL_EXISTS; |
| 3260 | if (do_vfs_lock(request->fl_file, request) == -ENOENT) | 3307 | down_read(&nfsi->rwsem); |
| 3308 | if (do_vfs_lock(request->fl_file, request) == -ENOENT) { | ||
| 3309 | up_read(&nfsi->rwsem); | ||
| 3261 | goto out; | 3310 | goto out; |
| 3311 | } | ||
| 3312 | up_read(&nfsi->rwsem); | ||
| 3262 | if (status != 0) | 3313 | if (status != 0) |
| 3263 | goto out; | 3314 | goto out; |
| 3264 | /* Is this a delegated lock? */ | 3315 | /* Is this a delegated lock? */ |
| @@ -3484,7 +3535,7 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request | |||
| 3484 | 3535 | ||
| 3485 | static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) | 3536 | static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) |
| 3486 | { | 3537 | { |
| 3487 | struct nfs_client *clp = state->owner->so_client; | 3538 | struct nfs_inode *nfsi = NFS_I(state->inode); |
| 3488 | unsigned char fl_flags = request->fl_flags; | 3539 | unsigned char fl_flags = request->fl_flags; |
| 3489 | int status; | 3540 | int status; |
| 3490 | 3541 | ||
| @@ -3496,19 +3547,13 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock | |||
| 3496 | status = do_vfs_lock(request->fl_file, request); | 3547 | status = do_vfs_lock(request->fl_file, request); |
| 3497 | if (status < 0) | 3548 | if (status < 0) |
| 3498 | goto out; | 3549 | goto out; |
| 3499 | down_read(&clp->cl_sem); | 3550 | down_read(&nfsi->rwsem); |
| 3500 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { | 3551 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { |
| 3501 | struct nfs_inode *nfsi = NFS_I(state->inode); | ||
| 3502 | /* Yes: cache locks! */ | 3552 | /* Yes: cache locks! */ |
| 3503 | down_read(&nfsi->rwsem); | ||
| 3504 | /* ...but avoid races with delegation recall... */ | 3553 | /* ...but avoid races with delegation recall... */ |
| 3505 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { | 3554 | request->fl_flags = fl_flags & ~FL_SLEEP; |
| 3506 | request->fl_flags = fl_flags & ~FL_SLEEP; | 3555 | status = do_vfs_lock(request->fl_file, request); |
| 3507 | status = do_vfs_lock(request->fl_file, request); | 3556 | goto out_unlock; |
| 3508 | up_read(&nfsi->rwsem); | ||
| 3509 | goto out_unlock; | ||
| 3510 | } | ||
| 3511 | up_read(&nfsi->rwsem); | ||
| 3512 | } | 3557 | } |
| 3513 | status = _nfs4_do_setlk(state, cmd, request, 0); | 3558 | status = _nfs4_do_setlk(state, cmd, request, 0); |
| 3514 | if (status != 0) | 3559 | if (status != 0) |
| @@ -3518,7 +3563,7 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock | |||
| 3518 | if (do_vfs_lock(request->fl_file, request) < 0) | 3563 | if (do_vfs_lock(request->fl_file, request) < 0) |
| 3519 | printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __func__); | 3564 | printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __func__); |
| 3520 | out_unlock: | 3565 | out_unlock: |
| 3521 | up_read(&clp->cl_sem); | 3566 | up_read(&nfsi->rwsem); |
| 3522 | out: | 3567 | out: |
| 3523 | request->fl_flags = fl_flags; | 3568 | request->fl_flags = fl_flags; |
| 3524 | return status; | 3569 | return status; |
| @@ -3664,11 +3709,15 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | |||
| 3664 | } | 3709 | } |
| 3665 | 3710 | ||
| 3666 | struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { | 3711 | struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { |
| 3712 | .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT, | ||
| 3713 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, | ||
| 3667 | .recover_open = nfs4_open_reclaim, | 3714 | .recover_open = nfs4_open_reclaim, |
| 3668 | .recover_lock = nfs4_lock_reclaim, | 3715 | .recover_lock = nfs4_lock_reclaim, |
| 3669 | }; | 3716 | }; |
| 3670 | 3717 | ||
| 3671 | struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops = { | 3718 | struct nfs4_state_recovery_ops nfs4_nograce_recovery_ops = { |
| 3719 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, | ||
| 3720 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, | ||
| 3672 | .recover_open = nfs4_open_expired, | 3721 | .recover_open = nfs4_open_expired, |
| 3673 | .recover_lock = nfs4_lock_expired, | 3722 | .recover_lock = nfs4_lock_expired, |
| 3674 | }; | 3723 | }; |
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c index 3305acbbe2ae..f524e932ff7b 100644 --- a/fs/nfs/nfs4renewd.c +++ b/fs/nfs/nfs4renewd.c | |||
| @@ -65,7 +65,6 @@ nfs4_renew_state(struct work_struct *work) | |||
| 65 | long lease, timeout; | 65 | long lease, timeout; |
| 66 | unsigned long last, now; | 66 | unsigned long last, now; |
| 67 | 67 | ||
| 68 | down_read(&clp->cl_sem); | ||
| 69 | dprintk("%s: start\n", __func__); | 68 | dprintk("%s: start\n", __func__); |
| 70 | /* Are there any active superblocks? */ | 69 | /* Are there any active superblocks? */ |
| 71 | if (list_empty(&clp->cl_superblocks)) | 70 | if (list_empty(&clp->cl_superblocks)) |
| @@ -77,17 +76,19 @@ nfs4_renew_state(struct work_struct *work) | |||
| 77 | timeout = (2 * lease) / 3 + (long)last - (long)now; | 76 | timeout = (2 * lease) / 3 + (long)last - (long)now; |
| 78 | /* Are we close to a lease timeout? */ | 77 | /* Are we close to a lease timeout? */ |
| 79 | if (time_after(now, last + lease/3)) { | 78 | if (time_after(now, last + lease/3)) { |
| 80 | cred = nfs4_get_renew_cred(clp); | 79 | cred = nfs4_get_renew_cred_locked(clp); |
| 80 | spin_unlock(&clp->cl_lock); | ||
| 81 | if (cred == NULL) { | 81 | if (cred == NULL) { |
| 82 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 82 | if (list_empty(&clp->cl_delegations)) { |
| 83 | spin_unlock(&clp->cl_lock); | 83 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); |
| 84 | goto out; | ||
| 85 | } | ||
| 84 | nfs_expire_all_delegations(clp); | 86 | nfs_expire_all_delegations(clp); |
| 85 | goto out; | 87 | } else { |
| 88 | /* Queue an asynchronous RENEW. */ | ||
| 89 | nfs4_proc_async_renew(clp, cred); | ||
| 90 | put_rpccred(cred); | ||
| 86 | } | 91 | } |
| 87 | spin_unlock(&clp->cl_lock); | ||
| 88 | /* Queue an asynchronous RENEW. */ | ||
| 89 | nfs4_proc_async_renew(clp, cred); | ||
| 90 | put_rpccred(cred); | ||
| 91 | timeout = (2 * lease) / 3; | 92 | timeout = (2 * lease) / 3; |
| 92 | spin_lock(&clp->cl_lock); | 93 | spin_lock(&clp->cl_lock); |
| 93 | } else | 94 | } else |
| @@ -100,12 +101,11 @@ nfs4_renew_state(struct work_struct *work) | |||
| 100 | cancel_delayed_work(&clp->cl_renewd); | 101 | cancel_delayed_work(&clp->cl_renewd); |
| 101 | schedule_delayed_work(&clp->cl_renewd, timeout); | 102 | schedule_delayed_work(&clp->cl_renewd, timeout); |
| 102 | spin_unlock(&clp->cl_lock); | 103 | spin_unlock(&clp->cl_lock); |
| 104 | nfs_expire_unreferenced_delegations(clp); | ||
| 103 | out: | 105 | out: |
| 104 | up_read(&clp->cl_sem); | ||
| 105 | dprintk("%s: done\n", __func__); | 106 | dprintk("%s: done\n", __func__); |
| 106 | } | 107 | } |
| 107 | 108 | ||
| 108 | /* Must be called with clp->cl_sem locked for writes */ | ||
| 109 | void | 109 | void |
| 110 | nfs4_schedule_state_renewal(struct nfs_client *clp) | 110 | nfs4_schedule_state_renewal(struct nfs_client *clp) |
| 111 | { | 111 | { |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 401ef8b28f97..2022fe47966f 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
| @@ -71,14 +71,12 @@ static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred) | |||
| 71 | return status; | 71 | return status; |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | static struct rpc_cred *nfs4_get_machine_cred(struct nfs_client *clp) | 74 | static struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp) |
| 75 | { | 75 | { |
| 76 | struct rpc_cred *cred = NULL; | 76 | struct rpc_cred *cred = NULL; |
| 77 | 77 | ||
| 78 | spin_lock(&clp->cl_lock); | ||
| 79 | if (clp->cl_machine_cred != NULL) | 78 | if (clp->cl_machine_cred != NULL) |
| 80 | cred = get_rpccred(clp->cl_machine_cred); | 79 | cred = get_rpccred(clp->cl_machine_cred); |
| 81 | spin_unlock(&clp->cl_lock); | ||
| 82 | return cred; | 80 | return cred; |
| 83 | } | 81 | } |
| 84 | 82 | ||
| @@ -94,7 +92,7 @@ static void nfs4_clear_machine_cred(struct nfs_client *clp) | |||
| 94 | put_rpccred(cred); | 92 | put_rpccred(cred); |
| 95 | } | 93 | } |
| 96 | 94 | ||
| 97 | struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp) | 95 | struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp) |
| 98 | { | 96 | { |
| 99 | struct nfs4_state_owner *sp; | 97 | struct nfs4_state_owner *sp; |
| 100 | struct rb_node *pos; | 98 | struct rb_node *pos; |
| @@ -110,13 +108,24 @@ struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp) | |||
| 110 | return cred; | 108 | return cred; |
| 111 | } | 109 | } |
| 112 | 110 | ||
| 111 | static struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp) | ||
| 112 | { | ||
| 113 | struct rpc_cred *cred; | ||
| 114 | |||
| 115 | spin_lock(&clp->cl_lock); | ||
| 116 | cred = nfs4_get_renew_cred_locked(clp); | ||
| 117 | spin_unlock(&clp->cl_lock); | ||
| 118 | return cred; | ||
| 119 | } | ||
| 120 | |||
| 113 | static struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp) | 121 | static struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp) |
| 114 | { | 122 | { |
| 115 | struct nfs4_state_owner *sp; | 123 | struct nfs4_state_owner *sp; |
| 116 | struct rb_node *pos; | 124 | struct rb_node *pos; |
| 117 | struct rpc_cred *cred; | 125 | struct rpc_cred *cred; |
| 118 | 126 | ||
| 119 | cred = nfs4_get_machine_cred(clp); | 127 | spin_lock(&clp->cl_lock); |
| 128 | cred = nfs4_get_machine_cred_locked(clp); | ||
| 120 | if (cred != NULL) | 129 | if (cred != NULL) |
| 121 | goto out; | 130 | goto out; |
| 122 | pos = rb_first(&clp->cl_state_owners); | 131 | pos = rb_first(&clp->cl_state_owners); |
| @@ -125,6 +134,7 @@ static struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp) | |||
| 125 | cred = get_rpccred(sp->so_cred); | 134 | cred = get_rpccred(sp->so_cred); |
| 126 | } | 135 | } |
| 127 | out: | 136 | out: |
| 137 | spin_unlock(&clp->cl_lock); | ||
| 128 | return cred; | 138 | return cred; |
| 129 | } | 139 | } |
| 130 | 140 | ||
| @@ -295,10 +305,6 @@ nfs4_drop_state_owner(struct nfs4_state_owner *sp) | |||
| 295 | } | 305 | } |
| 296 | } | 306 | } |
| 297 | 307 | ||
| 298 | /* | ||
| 299 | * Note: must be called with clp->cl_sem held in order to prevent races | ||
| 300 | * with reboot recovery! | ||
| 301 | */ | ||
| 302 | struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct rpc_cred *cred) | 308 | struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct rpc_cred *cred) |
| 303 | { | 309 | { |
| 304 | struct nfs_client *clp = server->nfs_client; | 310 | struct nfs_client *clp = server->nfs_client; |
| @@ -327,10 +333,6 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct | |||
| 327 | return sp; | 333 | return sp; |
| 328 | } | 334 | } |
| 329 | 335 | ||
| 330 | /* | ||
| 331 | * Must be called with clp->cl_sem held in order to avoid races | ||
| 332 | * with state recovery... | ||
| 333 | */ | ||
| 334 | void nfs4_put_state_owner(struct nfs4_state_owner *sp) | 336 | void nfs4_put_state_owner(struct nfs4_state_owner *sp) |
| 335 | { | 337 | { |
| 336 | struct nfs_client *clp = sp->so_client; | 338 | struct nfs_client *clp = sp->so_client; |
| @@ -361,18 +363,18 @@ nfs4_alloc_open_state(void) | |||
| 361 | } | 363 | } |
| 362 | 364 | ||
| 363 | void | 365 | void |
| 364 | nfs4_state_set_mode_locked(struct nfs4_state *state, mode_t mode) | 366 | nfs4_state_set_mode_locked(struct nfs4_state *state, fmode_t fmode) |
| 365 | { | 367 | { |
| 366 | if (state->state == mode) | 368 | if (state->state == fmode) |
| 367 | return; | 369 | return; |
| 368 | /* NB! List reordering - see the reclaim code for why. */ | 370 | /* NB! List reordering - see the reclaim code for why. */ |
| 369 | if ((mode & FMODE_WRITE) != (state->state & FMODE_WRITE)) { | 371 | if ((fmode & FMODE_WRITE) != (state->state & FMODE_WRITE)) { |
| 370 | if (mode & FMODE_WRITE) | 372 | if (fmode & FMODE_WRITE) |
| 371 | list_move(&state->open_states, &state->owner->so_states); | 373 | list_move(&state->open_states, &state->owner->so_states); |
| 372 | else | 374 | else |
| 373 | list_move_tail(&state->open_states, &state->owner->so_states); | 375 | list_move_tail(&state->open_states, &state->owner->so_states); |
| 374 | } | 376 | } |
| 375 | state->state = mode; | 377 | state->state = fmode; |
| 376 | } | 378 | } |
| 377 | 379 | ||
| 378 | static struct nfs4_state * | 380 | static struct nfs4_state * |
| @@ -432,10 +434,6 @@ out: | |||
| 432 | return state; | 434 | return state; |
| 433 | } | 435 | } |
| 434 | 436 | ||
| 435 | /* | ||
| 436 | * Beware! Caller must be holding exactly one | ||
| 437 | * reference to clp->cl_sem! | ||
| 438 | */ | ||
| 439 | void nfs4_put_open_state(struct nfs4_state *state) | 437 | void nfs4_put_open_state(struct nfs4_state *state) |
| 440 | { | 438 | { |
| 441 | struct inode *inode = state->inode; | 439 | struct inode *inode = state->inode; |
| @@ -456,16 +454,16 @@ void nfs4_put_open_state(struct nfs4_state *state) | |||
| 456 | /* | 454 | /* |
| 457 | * Close the current file. | 455 | * Close the current file. |
| 458 | */ | 456 | */ |
| 459 | static void __nfs4_close(struct path *path, struct nfs4_state *state, mode_t mode, int wait) | 457 | static void __nfs4_close(struct path *path, struct nfs4_state *state, fmode_t fmode, int wait) |
| 460 | { | 458 | { |
| 461 | struct nfs4_state_owner *owner = state->owner; | 459 | struct nfs4_state_owner *owner = state->owner; |
| 462 | int call_close = 0; | 460 | int call_close = 0; |
| 463 | int newstate; | 461 | fmode_t newstate; |
| 464 | 462 | ||
| 465 | atomic_inc(&owner->so_count); | 463 | atomic_inc(&owner->so_count); |
| 466 | /* Protect against nfs4_find_state() */ | 464 | /* Protect against nfs4_find_state() */ |
| 467 | spin_lock(&owner->so_lock); | 465 | spin_lock(&owner->so_lock); |
| 468 | switch (mode & (FMODE_READ | FMODE_WRITE)) { | 466 | switch (fmode & (FMODE_READ | FMODE_WRITE)) { |
| 469 | case FMODE_READ: | 467 | case FMODE_READ: |
| 470 | state->n_rdonly--; | 468 | state->n_rdonly--; |
| 471 | break; | 469 | break; |
| @@ -500,14 +498,14 @@ static void __nfs4_close(struct path *path, struct nfs4_state *state, mode_t mod | |||
| 500 | nfs4_do_close(path, state, wait); | 498 | nfs4_do_close(path, state, wait); |
| 501 | } | 499 | } |
| 502 | 500 | ||
| 503 | void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode) | 501 | void nfs4_close_state(struct path *path, struct nfs4_state *state, fmode_t fmode) |
| 504 | { | 502 | { |
| 505 | __nfs4_close(path, state, mode, 0); | 503 | __nfs4_close(path, state, fmode, 0); |
| 506 | } | 504 | } |
| 507 | 505 | ||
| 508 | void nfs4_close_sync(struct path *path, struct nfs4_state *state, mode_t mode) | 506 | void nfs4_close_sync(struct path *path, struct nfs4_state *state, fmode_t fmode) |
| 509 | { | 507 | { |
| 510 | __nfs4_close(path, state, mode, 1); | 508 | __nfs4_close(path, state, fmode, 1); |
| 511 | } | 509 | } |
| 512 | 510 | ||
| 513 | /* | 511 | /* |
| @@ -568,7 +566,6 @@ static void nfs4_free_lock_state(struct nfs4_lock_state *lsp) | |||
| 568 | * Return a compatible lock_state. If no initialized lock_state structure | 566 | * Return a compatible lock_state. If no initialized lock_state structure |
| 569 | * exists, return an uninitialized one. | 567 | * exists, return an uninitialized one. |
| 570 | * | 568 | * |
| 571 | * The caller must be holding clp->cl_sem | ||
| 572 | */ | 569 | */ |
| 573 | static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner) | 570 | static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner) |
| 574 | { | 571 | { |
| @@ -770,32 +767,34 @@ unlock: | |||
| 770 | return status; | 767 | return status; |
| 771 | } | 768 | } |
| 772 | 769 | ||
| 773 | static int reclaimer(void *); | 770 | static int nfs4_run_state_manager(void *); |
| 774 | 771 | ||
| 775 | static inline void nfs4_clear_recover_bit(struct nfs_client *clp) | 772 | static void nfs4_clear_state_manager_bit(struct nfs_client *clp) |
| 776 | { | 773 | { |
| 777 | smp_mb__before_clear_bit(); | 774 | smp_mb__before_clear_bit(); |
| 778 | clear_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state); | 775 | clear_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state); |
| 779 | smp_mb__after_clear_bit(); | 776 | smp_mb__after_clear_bit(); |
| 780 | wake_up_bit(&clp->cl_state, NFS4CLNT_STATE_RECOVER); | 777 | wake_up_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING); |
| 781 | rpc_wake_up(&clp->cl_rpcwaitq); | 778 | rpc_wake_up(&clp->cl_rpcwaitq); |
| 782 | } | 779 | } |
| 783 | 780 | ||
| 784 | /* | 781 | /* |
| 785 | * State recovery routine | 782 | * Schedule the nfs_client asynchronous state management routine |
| 786 | */ | 783 | */ |
| 787 | static void nfs4_recover_state(struct nfs_client *clp) | 784 | void nfs4_schedule_state_manager(struct nfs_client *clp) |
| 788 | { | 785 | { |
| 789 | struct task_struct *task; | 786 | struct task_struct *task; |
| 790 | 787 | ||
| 788 | if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0) | ||
| 789 | return; | ||
| 791 | __module_get(THIS_MODULE); | 790 | __module_get(THIS_MODULE); |
| 792 | atomic_inc(&clp->cl_count); | 791 | atomic_inc(&clp->cl_count); |
| 793 | task = kthread_run(reclaimer, clp, "%s-reclaim", | 792 | task = kthread_run(nfs4_run_state_manager, clp, "%s-manager", |
| 794 | rpc_peeraddr2str(clp->cl_rpcclient, | 793 | rpc_peeraddr2str(clp->cl_rpcclient, |
| 795 | RPC_DISPLAY_ADDR)); | 794 | RPC_DISPLAY_ADDR)); |
| 796 | if (!IS_ERR(task)) | 795 | if (!IS_ERR(task)) |
| 797 | return; | 796 | return; |
| 798 | nfs4_clear_recover_bit(clp); | 797 | nfs4_clear_state_manager_bit(clp); |
| 799 | nfs_put_client(clp); | 798 | nfs_put_client(clp); |
| 800 | module_put(THIS_MODULE); | 799 | module_put(THIS_MODULE); |
| 801 | } | 800 | } |
| @@ -807,16 +806,42 @@ void nfs4_schedule_state_recovery(struct nfs_client *clp) | |||
| 807 | { | 806 | { |
| 808 | if (!clp) | 807 | if (!clp) |
| 809 | return; | 808 | return; |
| 810 | if (test_and_set_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) == 0) | 809 | if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) |
| 811 | nfs4_recover_state(clp); | 810 | set_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); |
| 811 | nfs4_schedule_state_manager(clp); | ||
| 812 | } | 812 | } |
| 813 | 813 | ||
| 814 | static int nfs4_reclaim_locks(struct nfs4_state_recovery_ops *ops, struct nfs4_state *state) | 814 | static int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state) |
| 815 | { | ||
| 816 | |||
| 817 | set_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags); | ||
| 818 | /* Don't recover state that expired before the reboot */ | ||
| 819 | if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags)) { | ||
| 820 | clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags); | ||
| 821 | return 0; | ||
| 822 | } | ||
| 823 | set_bit(NFS_OWNER_RECLAIM_REBOOT, &state->owner->so_flags); | ||
| 824 | set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state); | ||
| 825 | return 1; | ||
| 826 | } | ||
| 827 | |||
| 828 | int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state) | ||
| 829 | { | ||
| 830 | set_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags); | ||
| 831 | clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags); | ||
| 832 | set_bit(NFS_OWNER_RECLAIM_NOGRACE, &state->owner->so_flags); | ||
| 833 | set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state); | ||
| 834 | return 1; | ||
| 835 | } | ||
| 836 | |||
| 837 | static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops) | ||
| 815 | { | 838 | { |
| 816 | struct inode *inode = state->inode; | 839 | struct inode *inode = state->inode; |
| 840 | struct nfs_inode *nfsi = NFS_I(inode); | ||
| 817 | struct file_lock *fl; | 841 | struct file_lock *fl; |
| 818 | int status = 0; | 842 | int status = 0; |
| 819 | 843 | ||
| 844 | down_write(&nfsi->rwsem); | ||
| 820 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { | 845 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { |
| 821 | if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) | 846 | if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) |
| 822 | continue; | 847 | continue; |
| @@ -839,12 +864,14 @@ static int nfs4_reclaim_locks(struct nfs4_state_recovery_ops *ops, struct nfs4_s | |||
| 839 | goto out_err; | 864 | goto out_err; |
| 840 | } | 865 | } |
| 841 | } | 866 | } |
| 867 | up_write(&nfsi->rwsem); | ||
| 842 | return 0; | 868 | return 0; |
| 843 | out_err: | 869 | out_err: |
| 870 | up_write(&nfsi->rwsem); | ||
| 844 | return status; | 871 | return status; |
| 845 | } | 872 | } |
| 846 | 873 | ||
| 847 | static int nfs4_reclaim_open_state(struct nfs4_state_recovery_ops *ops, struct nfs4_state_owner *sp) | 874 | static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs4_state_recovery_ops *ops) |
| 848 | { | 875 | { |
| 849 | struct nfs4_state *state; | 876 | struct nfs4_state *state; |
| 850 | struct nfs4_lock_state *lock; | 877 | struct nfs4_lock_state *lock; |
| @@ -858,28 +885,34 @@ static int nfs4_reclaim_open_state(struct nfs4_state_recovery_ops *ops, struct n | |||
| 858 | * recovering after a network partition or a reboot from a | 885 | * recovering after a network partition or a reboot from a |
| 859 | * server that doesn't support a grace period. | 886 | * server that doesn't support a grace period. |
| 860 | */ | 887 | */ |
| 888 | restart: | ||
| 889 | spin_lock(&sp->so_lock); | ||
| 861 | list_for_each_entry(state, &sp->so_states, open_states) { | 890 | list_for_each_entry(state, &sp->so_states, open_states) { |
| 891 | if (!test_and_clear_bit(ops->state_flag_bit, &state->flags)) | ||
| 892 | continue; | ||
| 862 | if (state->state == 0) | 893 | if (state->state == 0) |
| 863 | continue; | 894 | continue; |
| 895 | atomic_inc(&state->count); | ||
| 896 | spin_unlock(&sp->so_lock); | ||
| 864 | status = ops->recover_open(sp, state); | 897 | status = ops->recover_open(sp, state); |
| 865 | if (status >= 0) { | 898 | if (status >= 0) { |
| 866 | status = nfs4_reclaim_locks(ops, state); | 899 | status = nfs4_reclaim_locks(state, ops); |
| 867 | if (status < 0) | 900 | if (status >= 0) { |
| 868 | goto out_err; | 901 | list_for_each_entry(lock, &state->lock_states, ls_locks) { |
| 869 | list_for_each_entry(lock, &state->lock_states, ls_locks) { | 902 | if (!(lock->ls_flags & NFS_LOCK_INITIALIZED)) |
| 870 | if (!(lock->ls_flags & NFS_LOCK_INITIALIZED)) | 903 | printk("%s: Lock reclaim failed!\n", |
| 871 | printk("%s: Lock reclaim failed!\n", | ||
| 872 | __func__); | 904 | __func__); |
| 905 | } | ||
| 906 | nfs4_put_open_state(state); | ||
| 907 | goto restart; | ||
| 873 | } | 908 | } |
| 874 | continue; | ||
| 875 | } | 909 | } |
| 876 | switch (status) { | 910 | switch (status) { |
| 877 | default: | 911 | default: |
| 878 | printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", | 912 | printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", |
| 879 | __func__, status); | 913 | __func__, status); |
| 880 | case -ENOENT: | 914 | case -ENOENT: |
| 881 | case -NFS4ERR_RECLAIM_BAD: | 915 | case -ESTALE: |
| 882 | case -NFS4ERR_RECLAIM_CONFLICT: | ||
| 883 | /* | 916 | /* |
| 884 | * Open state on this file cannot be recovered | 917 | * Open state on this file cannot be recovered |
| 885 | * All we can do is revert to using the zero stateid. | 918 | * All we can do is revert to using the zero stateid. |
| @@ -889,84 +922,176 @@ static int nfs4_reclaim_open_state(struct nfs4_state_recovery_ops *ops, struct n | |||
| 889 | /* Mark the file as being 'closed' */ | 922 | /* Mark the file as being 'closed' */ |
| 890 | state->state = 0; | 923 | state->state = 0; |
| 891 | break; | 924 | break; |
| 925 | case -NFS4ERR_RECLAIM_BAD: | ||
| 926 | case -NFS4ERR_RECLAIM_CONFLICT: | ||
| 927 | nfs4_state_mark_reclaim_nograce(sp->so_client, state); | ||
| 928 | break; | ||
| 892 | case -NFS4ERR_EXPIRED: | 929 | case -NFS4ERR_EXPIRED: |
| 893 | case -NFS4ERR_NO_GRACE: | 930 | case -NFS4ERR_NO_GRACE: |
| 931 | nfs4_state_mark_reclaim_nograce(sp->so_client, state); | ||
| 894 | case -NFS4ERR_STALE_CLIENTID: | 932 | case -NFS4ERR_STALE_CLIENTID: |
| 895 | goto out_err; | 933 | goto out_err; |
| 896 | } | 934 | } |
| 935 | nfs4_put_open_state(state); | ||
| 936 | goto restart; | ||
| 897 | } | 937 | } |
| 938 | spin_unlock(&sp->so_lock); | ||
| 898 | return 0; | 939 | return 0; |
| 899 | out_err: | 940 | out_err: |
| 941 | nfs4_put_open_state(state); | ||
| 900 | return status; | 942 | return status; |
| 901 | } | 943 | } |
| 902 | 944 | ||
| 903 | static void nfs4_state_mark_reclaim(struct nfs_client *clp) | 945 | static void nfs4_clear_open_state(struct nfs4_state *state) |
| 946 | { | ||
| 947 | struct nfs4_lock_state *lock; | ||
| 948 | |||
| 949 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | ||
| 950 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); | ||
| 951 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
| 952 | clear_bit(NFS_O_RDWR_STATE, &state->flags); | ||
| 953 | list_for_each_entry(lock, &state->lock_states, ls_locks) { | ||
| 954 | lock->ls_seqid.flags = 0; | ||
| 955 | lock->ls_flags &= ~NFS_LOCK_INITIALIZED; | ||
| 956 | } | ||
| 957 | } | ||
| 958 | |||
| 959 | static void nfs4_state_mark_reclaim_helper(struct nfs_client *clp, int (*mark_reclaim)(struct nfs_client *clp, struct nfs4_state *state)) | ||
| 904 | { | 960 | { |
| 905 | struct nfs4_state_owner *sp; | 961 | struct nfs4_state_owner *sp; |
| 906 | struct rb_node *pos; | 962 | struct rb_node *pos; |
| 907 | struct nfs4_state *state; | 963 | struct nfs4_state *state; |
| 908 | struct nfs4_lock_state *lock; | ||
| 909 | 964 | ||
| 910 | /* Reset all sequence ids to zero */ | 965 | /* Reset all sequence ids to zero */ |
| 911 | for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) { | 966 | for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) { |
| 912 | sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); | 967 | sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); |
| 913 | sp->so_seqid.counter = 0; | ||
| 914 | sp->so_seqid.flags = 0; | 968 | sp->so_seqid.flags = 0; |
| 915 | spin_lock(&sp->so_lock); | 969 | spin_lock(&sp->so_lock); |
| 916 | list_for_each_entry(state, &sp->so_states, open_states) { | 970 | list_for_each_entry(state, &sp->so_states, open_states) { |
| 917 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | 971 | if (mark_reclaim(clp, state)) |
| 918 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); | 972 | nfs4_clear_open_state(state); |
| 919 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
| 920 | clear_bit(NFS_O_RDWR_STATE, &state->flags); | ||
| 921 | list_for_each_entry(lock, &state->lock_states, ls_locks) { | ||
| 922 | lock->ls_seqid.counter = 0; | ||
| 923 | lock->ls_seqid.flags = 0; | ||
| 924 | lock->ls_flags &= ~NFS_LOCK_INITIALIZED; | ||
| 925 | } | ||
| 926 | } | 973 | } |
| 927 | spin_unlock(&sp->so_lock); | 974 | spin_unlock(&sp->so_lock); |
| 928 | } | 975 | } |
| 929 | } | 976 | } |
| 930 | 977 | ||
| 931 | static int reclaimer(void *ptr) | 978 | static void nfs4_state_start_reclaim_reboot(struct nfs_client *clp) |
| 979 | { | ||
| 980 | /* Mark all delegations for reclaim */ | ||
| 981 | nfs_delegation_mark_reclaim(clp); | ||
| 982 | nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_reboot); | ||
| 983 | } | ||
| 984 | |||
| 985 | static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp) | ||
| 932 | { | 986 | { |
| 933 | struct nfs_client *clp = ptr; | ||
| 934 | struct nfs4_state_owner *sp; | 987 | struct nfs4_state_owner *sp; |
| 935 | struct rb_node *pos; | 988 | struct rb_node *pos; |
| 936 | struct nfs4_state_recovery_ops *ops; | 989 | struct nfs4_state *state; |
| 937 | struct rpc_cred *cred; | 990 | |
| 991 | if (!test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) | ||
| 992 | return; | ||
| 993 | |||
| 994 | for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) { | ||
| 995 | sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); | ||
| 996 | spin_lock(&sp->so_lock); | ||
| 997 | list_for_each_entry(state, &sp->so_states, open_states) { | ||
| 998 | if (!test_and_clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags)) | ||
| 999 | continue; | ||
| 1000 | nfs4_state_mark_reclaim_nograce(clp, state); | ||
| 1001 | } | ||
| 1002 | spin_unlock(&sp->so_lock); | ||
| 1003 | } | ||
| 1004 | |||
| 1005 | nfs_delegation_reap_unclaimed(clp); | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | static void nfs_delegation_clear_all(struct nfs_client *clp) | ||
| 1009 | { | ||
| 1010 | nfs_delegation_mark_reclaim(clp); | ||
| 1011 | nfs_delegation_reap_unclaimed(clp); | ||
| 1012 | } | ||
| 1013 | |||
| 1014 | static void nfs4_state_start_reclaim_nograce(struct nfs_client *clp) | ||
| 1015 | { | ||
| 1016 | nfs_delegation_clear_all(clp); | ||
| 1017 | nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_nograce); | ||
| 1018 | } | ||
| 1019 | |||
| 1020 | static void nfs4_state_end_reclaim_nograce(struct nfs_client *clp) | ||
| 1021 | { | ||
| 1022 | clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state); | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | static void nfs4_recovery_handle_error(struct nfs_client *clp, int error) | ||
| 1026 | { | ||
| 1027 | switch (error) { | ||
| 1028 | case -NFS4ERR_CB_PATH_DOWN: | ||
| 1029 | nfs_handle_cb_pathdown(clp); | ||
| 1030 | break; | ||
| 1031 | case -NFS4ERR_STALE_CLIENTID: | ||
| 1032 | case -NFS4ERR_LEASE_MOVED: | ||
| 1033 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
| 1034 | nfs4_state_start_reclaim_reboot(clp); | ||
| 1035 | break; | ||
| 1036 | case -NFS4ERR_EXPIRED: | ||
| 1037 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
| 1038 | nfs4_state_start_reclaim_nograce(clp); | ||
| 1039 | } | ||
| 1040 | } | ||
| 1041 | |||
| 1042 | static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recovery_ops *ops) | ||
| 1043 | { | ||
| 1044 | struct rb_node *pos; | ||
| 938 | int status = 0; | 1045 | int status = 0; |
| 939 | 1046 | ||
| 940 | allow_signal(SIGKILL); | 1047 | restart: |
| 1048 | spin_lock(&clp->cl_lock); | ||
| 1049 | for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) { | ||
| 1050 | struct nfs4_state_owner *sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); | ||
| 1051 | if (!test_and_clear_bit(ops->owner_flag_bit, &sp->so_flags)) | ||
| 1052 | continue; | ||
| 1053 | atomic_inc(&sp->so_count); | ||
| 1054 | spin_unlock(&clp->cl_lock); | ||
| 1055 | status = nfs4_reclaim_open_state(sp, ops); | ||
| 1056 | if (status < 0) { | ||
| 1057 | set_bit(ops->owner_flag_bit, &sp->so_flags); | ||
| 1058 | nfs4_put_state_owner(sp); | ||
| 1059 | nfs4_recovery_handle_error(clp, status); | ||
| 1060 | return status; | ||
| 1061 | } | ||
| 1062 | nfs4_put_state_owner(sp); | ||
| 1063 | goto restart; | ||
| 1064 | } | ||
| 1065 | spin_unlock(&clp->cl_lock); | ||
| 1066 | return status; | ||
| 1067 | } | ||
| 941 | 1068 | ||
| 942 | /* Ensure exclusive access to NFSv4 state */ | 1069 | static int nfs4_check_lease(struct nfs_client *clp) |
| 943 | down_write(&clp->cl_sem); | 1070 | { |
| 944 | /* Are there any NFS mounts out there? */ | 1071 | struct rpc_cred *cred; |
| 945 | if (list_empty(&clp->cl_superblocks)) | 1072 | int status = -NFS4ERR_EXPIRED; |
| 946 | goto out; | 1073 | |
| 947 | restart_loop: | 1074 | /* Is the client already known to have an expired lease? */ |
| 948 | ops = &nfs4_network_partition_recovery_ops; | 1075 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) |
| 949 | /* Are there any open files on this volume? */ | 1076 | return 0; |
| 950 | cred = nfs4_get_renew_cred(clp); | 1077 | cred = nfs4_get_renew_cred(clp); |
| 951 | if (cred != NULL) { | 1078 | if (cred == NULL) { |
| 952 | /* Yes there are: try to renew the old lease */ | 1079 | cred = nfs4_get_setclientid_cred(clp); |
| 953 | status = nfs4_proc_renew(clp, cred); | 1080 | if (cred == NULL) |
| 954 | put_rpccred(cred); | 1081 | goto out; |
| 955 | switch (status) { | ||
| 956 | case 0: | ||
| 957 | case -NFS4ERR_CB_PATH_DOWN: | ||
| 958 | goto out; | ||
| 959 | case -NFS4ERR_STALE_CLIENTID: | ||
| 960 | case -NFS4ERR_LEASE_MOVED: | ||
| 961 | ops = &nfs4_reboot_recovery_ops; | ||
| 962 | } | ||
| 963 | } else { | ||
| 964 | /* "reboot" to ensure we clear all state on the server */ | ||
| 965 | clp->cl_boot_time = CURRENT_TIME; | ||
| 966 | } | 1082 | } |
| 967 | /* We're going to have to re-establish a clientid */ | 1083 | status = nfs4_proc_renew(clp, cred); |
| 968 | nfs4_state_mark_reclaim(clp); | 1084 | put_rpccred(cred); |
| 969 | status = -ENOENT; | 1085 | out: |
| 1086 | nfs4_recovery_handle_error(clp, status); | ||
| 1087 | return status; | ||
| 1088 | } | ||
| 1089 | |||
| 1090 | static int nfs4_reclaim_lease(struct nfs_client *clp) | ||
| 1091 | { | ||
| 1092 | struct rpc_cred *cred; | ||
| 1093 | int status = -ENOENT; | ||
| 1094 | |||
| 970 | cred = nfs4_get_setclientid_cred(clp); | 1095 | cred = nfs4_get_setclientid_cred(clp); |
| 971 | if (cred != NULL) { | 1096 | if (cred != NULL) { |
| 972 | status = nfs4_init_client(clp, cred); | 1097 | status = nfs4_init_client(clp, cred); |
| @@ -974,42 +1099,90 @@ restart_loop: | |||
| 974 | /* Handle case where the user hasn't set up machine creds */ | 1099 | /* Handle case where the user hasn't set up machine creds */ |
| 975 | if (status == -EACCES && cred == clp->cl_machine_cred) { | 1100 | if (status == -EACCES && cred == clp->cl_machine_cred) { |
| 976 | nfs4_clear_machine_cred(clp); | 1101 | nfs4_clear_machine_cred(clp); |
| 977 | goto restart_loop; | 1102 | status = -EAGAIN; |
| 978 | } | 1103 | } |
| 979 | } | 1104 | } |
| 980 | if (status) | 1105 | return status; |
| 981 | goto out_error; | 1106 | } |
| 982 | /* Mark all delegations for reclaim */ | 1107 | |
| 983 | nfs_delegation_mark_reclaim(clp); | 1108 | static void nfs4_state_manager(struct nfs_client *clp) |
| 984 | /* Note: list is protected by exclusive lock on cl->cl_sem */ | 1109 | { |
| 985 | for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) { | 1110 | int status = 0; |
| 986 | sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); | 1111 | |
| 987 | status = nfs4_reclaim_open_state(ops, sp); | 1112 | /* Ensure exclusive access to NFSv4 state */ |
| 988 | if (status < 0) { | 1113 | for(;;) { |
| 989 | if (status == -NFS4ERR_NO_GRACE) { | 1114 | if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) { |
| 990 | ops = &nfs4_network_partition_recovery_ops; | 1115 | /* We're going to have to re-establish a clientid */ |
| 991 | status = nfs4_reclaim_open_state(ops, sp); | 1116 | status = nfs4_reclaim_lease(clp); |
| 1117 | if (status) { | ||
| 1118 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
| 1119 | if (status == -EAGAIN) | ||
| 1120 | continue; | ||
| 1121 | goto out_error; | ||
| 992 | } | 1122 | } |
| 1123 | clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); | ||
| 1124 | } | ||
| 1125 | |||
| 1126 | if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) { | ||
| 1127 | status = nfs4_check_lease(clp); | ||
| 1128 | if (status != 0) | ||
| 1129 | continue; | ||
| 1130 | } | ||
| 1131 | |||
| 1132 | /* First recover reboot state... */ | ||
| 1133 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) { | ||
| 1134 | status = nfs4_do_reclaim(clp, &nfs4_reboot_recovery_ops); | ||
| 993 | if (status == -NFS4ERR_STALE_CLIENTID) | 1135 | if (status == -NFS4ERR_STALE_CLIENTID) |
| 994 | goto restart_loop; | 1136 | continue; |
| 995 | if (status == -NFS4ERR_EXPIRED) | 1137 | nfs4_state_end_reclaim_reboot(clp); |
| 996 | goto restart_loop; | 1138 | continue; |
| 1139 | } | ||
| 1140 | |||
| 1141 | /* Now recover expired state... */ | ||
| 1142 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) { | ||
| 1143 | status = nfs4_do_reclaim(clp, &nfs4_nograce_recovery_ops); | ||
| 1144 | if (status < 0) { | ||
| 1145 | set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state); | ||
| 1146 | if (status == -NFS4ERR_STALE_CLIENTID) | ||
| 1147 | continue; | ||
| 1148 | if (status == -NFS4ERR_EXPIRED) | ||
| 1149 | continue; | ||
| 1150 | goto out_error; | ||
| 1151 | } else | ||
| 1152 | nfs4_state_end_reclaim_nograce(clp); | ||
| 1153 | continue; | ||
| 997 | } | 1154 | } |
| 1155 | |||
| 1156 | if (test_and_clear_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) { | ||
| 1157 | nfs_client_return_marked_delegations(clp); | ||
| 1158 | continue; | ||
| 1159 | } | ||
| 1160 | |||
| 1161 | nfs4_clear_state_manager_bit(clp); | ||
| 1162 | /* Did we race with an attempt to give us more work? */ | ||
| 1163 | if (clp->cl_state == 0) | ||
| 1164 | break; | ||
| 1165 | if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0) | ||
| 1166 | break; | ||
| 998 | } | 1167 | } |
| 999 | nfs_delegation_reap_unclaimed(clp); | 1168 | return; |
| 1000 | out: | 1169 | out_error: |
| 1001 | up_write(&clp->cl_sem); | 1170 | printk(KERN_WARNING "Error: state manager failed on NFSv4 server %s" |
| 1002 | if (status == -NFS4ERR_CB_PATH_DOWN) | 1171 | " with error %d\n", clp->cl_hostname, -status); |
| 1003 | nfs_handle_cb_pathdown(clp); | 1172 | if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) |
| 1004 | nfs4_clear_recover_bit(clp); | 1173 | nfs4_state_end_reclaim_reboot(clp); |
| 1174 | nfs4_clear_state_manager_bit(clp); | ||
| 1175 | } | ||
| 1176 | |||
| 1177 | static int nfs4_run_state_manager(void *ptr) | ||
| 1178 | { | ||
| 1179 | struct nfs_client *clp = ptr; | ||
| 1180 | |||
| 1181 | allow_signal(SIGKILL); | ||
| 1182 | nfs4_state_manager(clp); | ||
| 1005 | nfs_put_client(clp); | 1183 | nfs_put_client(clp); |
| 1006 | module_put_and_exit(0); | 1184 | module_put_and_exit(0); |
| 1007 | return 0; | 1185 | return 0; |
| 1008 | out_error: | ||
| 1009 | printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %s" | ||
| 1010 | " with error %d\n", clp->cl_hostname, -status); | ||
| 1011 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
| 1012 | goto out; | ||
| 1013 | } | 1186 | } |
| 1014 | 1187 | ||
| 1015 | /* | 1188 | /* |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index b916297d2334..d1e4c8f8a0a9 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
| @@ -8,7 +8,7 @@ | |||
| 8 | * | 8 | * |
| 9 | * Kendrick Smith <kmsmith@umich.edu> | 9 | * Kendrick Smith <kmsmith@umich.edu> |
| 10 | * Andy Adamson <andros@umich.edu> | 10 | * Andy Adamson <andros@umich.edu> |
| 11 | * | 11 | * |
| 12 | * Redistribution and use in source and binary forms, with or without | 12 | * Redistribution and use in source and binary forms, with or without |
| 13 | * modification, are permitted provided that the following conditions | 13 | * modification, are permitted provided that the following conditions |
| 14 | * are met: | 14 | * are met: |
| @@ -67,7 +67,7 @@ static int nfs4_stat_to_errno(int); | |||
| 67 | #define NFS4_MAXTAGLEN 0 | 67 | #define NFS4_MAXTAGLEN 0 |
| 68 | #endif | 68 | #endif |
| 69 | 69 | ||
| 70 | /* lock,open owner id: | 70 | /* lock,open owner id: |
| 71 | * we currently use size 2 (u64) out of (NFS4_OPAQUE_LIMIT >> 2) | 71 | * we currently use size 2 (u64) out of (NFS4_OPAQUE_LIMIT >> 2) |
| 72 | */ | 72 | */ |
| 73 | #define open_owner_id_maxsz (1 + 4) | 73 | #define open_owner_id_maxsz (1 + 4) |
| @@ -541,6 +541,7 @@ static struct { | |||
| 541 | struct compound_hdr { | 541 | struct compound_hdr { |
| 542 | int32_t status; | 542 | int32_t status; |
| 543 | uint32_t nops; | 543 | uint32_t nops; |
| 544 | __be32 * nops_p; | ||
| 544 | uint32_t taglen; | 545 | uint32_t taglen; |
| 545 | char * tag; | 546 | char * tag; |
| 546 | }; | 547 | }; |
| @@ -578,7 +579,7 @@ static void encode_string(struct xdr_stream *xdr, unsigned int len, const char * | |||
| 578 | xdr_encode_opaque(p, str, len); | 579 | xdr_encode_opaque(p, str, len); |
| 579 | } | 580 | } |
| 580 | 581 | ||
| 581 | static int encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) | 582 | static void encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) |
| 582 | { | 583 | { |
| 583 | __be32 *p; | 584 | __be32 *p; |
| 584 | 585 | ||
| @@ -588,8 +589,13 @@ static int encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
| 588 | WRITE32(hdr->taglen); | 589 | WRITE32(hdr->taglen); |
| 589 | WRITEMEM(hdr->tag, hdr->taglen); | 590 | WRITEMEM(hdr->tag, hdr->taglen); |
| 590 | WRITE32(NFS4_MINOR_VERSION); | 591 | WRITE32(NFS4_MINOR_VERSION); |
| 592 | hdr->nops_p = p; | ||
| 591 | WRITE32(hdr->nops); | 593 | WRITE32(hdr->nops); |
| 592 | return 0; | 594 | } |
| 595 | |||
| 596 | static void encode_nops(struct compound_hdr *hdr) | ||
| 597 | { | ||
| 598 | *hdr->nops_p = htonl(hdr->nops); | ||
| 593 | } | 599 | } |
| 594 | 600 | ||
| 595 | static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *verf) | 601 | static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *verf) |
| @@ -601,7 +607,7 @@ static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *ve | |||
| 601 | xdr_encode_opaque_fixed(p, verf->data, NFS4_VERIFIER_SIZE); | 607 | xdr_encode_opaque_fixed(p, verf->data, NFS4_VERIFIER_SIZE); |
| 602 | } | 608 | } |
| 603 | 609 | ||
| 604 | static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server) | 610 | static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server) |
| 605 | { | 611 | { |
| 606 | char owner_name[IDMAP_NAMESZ]; | 612 | char owner_name[IDMAP_NAMESZ]; |
| 607 | char owner_group[IDMAP_NAMESZ]; | 613 | char owner_group[IDMAP_NAMESZ]; |
| @@ -612,7 +618,6 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s | |||
| 612 | int len; | 618 | int len; |
| 613 | uint32_t bmval0 = 0; | 619 | uint32_t bmval0 = 0; |
| 614 | uint32_t bmval1 = 0; | 620 | uint32_t bmval1 = 0; |
| 615 | int status; | ||
| 616 | 621 | ||
| 617 | /* | 622 | /* |
| 618 | * We reserve enough space to write the entire attribute buffer at once. | 623 | * We reserve enough space to write the entire attribute buffer at once. |
| @@ -709,7 +714,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s | |||
| 709 | bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET; | 714 | bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET; |
| 710 | WRITE32(NFS4_SET_TO_SERVER_TIME); | 715 | WRITE32(NFS4_SET_TO_SERVER_TIME); |
| 711 | } | 716 | } |
| 712 | 717 | ||
| 713 | /* | 718 | /* |
| 714 | * Now we backfill the bitmap and the attribute buffer length. | 719 | * Now we backfill the bitmap and the attribute buffer length. |
| 715 | */ | 720 | */ |
| @@ -723,23 +728,20 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s | |||
| 723 | *q++ = htonl(bmval1); | 728 | *q++ = htonl(bmval1); |
| 724 | *q++ = htonl(len); | 729 | *q++ = htonl(len); |
| 725 | 730 | ||
| 726 | status = 0; | ||
| 727 | /* out: */ | 731 | /* out: */ |
| 728 | return status; | ||
| 729 | } | 732 | } |
| 730 | 733 | ||
| 731 | static int encode_access(struct xdr_stream *xdr, u32 access) | 734 | static void encode_access(struct xdr_stream *xdr, u32 access, struct compound_hdr *hdr) |
| 732 | { | 735 | { |
| 733 | __be32 *p; | 736 | __be32 *p; |
| 734 | 737 | ||
| 735 | RESERVE_SPACE(8); | 738 | RESERVE_SPACE(8); |
| 736 | WRITE32(OP_ACCESS); | 739 | WRITE32(OP_ACCESS); |
| 737 | WRITE32(access); | 740 | WRITE32(access); |
| 738 | 741 | hdr->nops++; | |
| 739 | return 0; | ||
| 740 | } | 742 | } |
| 741 | 743 | ||
| 742 | static int encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg) | 744 | static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr) |
| 743 | { | 745 | { |
| 744 | __be32 *p; | 746 | __be32 *p; |
| 745 | 747 | ||
| @@ -747,26 +749,24 @@ static int encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg) | |||
| 747 | WRITE32(OP_CLOSE); | 749 | WRITE32(OP_CLOSE); |
| 748 | WRITE32(arg->seqid->sequence->counter); | 750 | WRITE32(arg->seqid->sequence->counter); |
| 749 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); | 751 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); |
| 750 | 752 | hdr->nops++; | |
| 751 | return 0; | ||
| 752 | } | 753 | } |
| 753 | 754 | ||
| 754 | static int encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args) | 755 | static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr) |
| 755 | { | 756 | { |
| 756 | __be32 *p; | 757 | __be32 *p; |
| 757 | |||
| 758 | RESERVE_SPACE(16); | ||
| 759 | WRITE32(OP_COMMIT); | ||
| 760 | WRITE64(args->offset); | ||
| 761 | WRITE32(args->count); | ||
| 762 | 758 | ||
| 763 | return 0; | 759 | RESERVE_SPACE(16); |
| 760 | WRITE32(OP_COMMIT); | ||
| 761 | WRITE64(args->offset); | ||
| 762 | WRITE32(args->count); | ||
| 763 | hdr->nops++; | ||
| 764 | } | 764 | } |
| 765 | 765 | ||
| 766 | static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create) | 766 | static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create, struct compound_hdr *hdr) |
| 767 | { | 767 | { |
| 768 | __be32 *p; | 768 | __be32 *p; |
| 769 | 769 | ||
| 770 | RESERVE_SPACE(8); | 770 | RESERVE_SPACE(8); |
| 771 | WRITE32(OP_CREATE); | 771 | WRITE32(OP_CREATE); |
| 772 | WRITE32(create->ftype); | 772 | WRITE32(create->ftype); |
| @@ -791,64 +791,62 @@ static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *c | |||
| 791 | RESERVE_SPACE(4 + create->name->len); | 791 | RESERVE_SPACE(4 + create->name->len); |
| 792 | WRITE32(create->name->len); | 792 | WRITE32(create->name->len); |
| 793 | WRITEMEM(create->name->name, create->name->len); | 793 | WRITEMEM(create->name->name, create->name->len); |
| 794 | hdr->nops++; | ||
| 794 | 795 | ||
| 795 | return encode_attrs(xdr, create->attrs, create->server); | 796 | encode_attrs(xdr, create->attrs, create->server); |
| 796 | } | 797 | } |
| 797 | 798 | ||
| 798 | static int encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap) | 799 | static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct compound_hdr *hdr) |
| 799 | { | 800 | { |
| 800 | __be32 *p; | 801 | __be32 *p; |
| 801 | 802 | ||
| 802 | RESERVE_SPACE(12); | 803 | RESERVE_SPACE(12); |
| 803 | WRITE32(OP_GETATTR); | 804 | WRITE32(OP_GETATTR); |
| 804 | WRITE32(1); | 805 | WRITE32(1); |
| 805 | WRITE32(bitmap); | 806 | WRITE32(bitmap); |
| 806 | return 0; | 807 | hdr->nops++; |
| 807 | } | 808 | } |
| 808 | 809 | ||
| 809 | static int encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1) | 810 | static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1, struct compound_hdr *hdr) |
| 810 | { | 811 | { |
| 811 | __be32 *p; | 812 | __be32 *p; |
| 812 | 813 | ||
| 813 | RESERVE_SPACE(16); | 814 | RESERVE_SPACE(16); |
| 814 | WRITE32(OP_GETATTR); | 815 | WRITE32(OP_GETATTR); |
| 815 | WRITE32(2); | 816 | WRITE32(2); |
| 816 | WRITE32(bm0); | 817 | WRITE32(bm0); |
| 817 | WRITE32(bm1); | 818 | WRITE32(bm1); |
| 818 | return 0; | 819 | hdr->nops++; |
| 819 | } | 820 | } |
| 820 | 821 | ||
| 821 | static int encode_getfattr(struct xdr_stream *xdr, const u32* bitmask) | 822 | static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr) |
| 822 | { | 823 | { |
| 823 | return encode_getattr_two(xdr, | 824 | encode_getattr_two(xdr, bitmask[0] & nfs4_fattr_bitmap[0], |
| 824 | bitmask[0] & nfs4_fattr_bitmap[0], | 825 | bitmask[1] & nfs4_fattr_bitmap[1], hdr); |
| 825 | bitmask[1] & nfs4_fattr_bitmap[1]); | ||
| 826 | } | 826 | } |
| 827 | 827 | ||
| 828 | static int encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask) | 828 | static void encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr) |
| 829 | { | 829 | { |
| 830 | return encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0], | 830 | encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0], |
| 831 | bitmask[1] & nfs4_fsinfo_bitmap[1]); | 831 | bitmask[1] & nfs4_fsinfo_bitmap[1], hdr); |
| 832 | } | 832 | } |
| 833 | 833 | ||
| 834 | static int encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask) | 834 | static void encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr) |
| 835 | { | 835 | { |
| 836 | return encode_getattr_two(xdr, | 836 | encode_getattr_two(xdr, bitmask[0] & nfs4_fs_locations_bitmap[0], |
| 837 | bitmask[0] & nfs4_fs_locations_bitmap[0], | 837 | bitmask[1] & nfs4_fs_locations_bitmap[1], hdr); |
| 838 | bitmask[1] & nfs4_fs_locations_bitmap[1]); | ||
| 839 | } | 838 | } |
| 840 | 839 | ||
| 841 | static int encode_getfh(struct xdr_stream *xdr) | 840 | static void encode_getfh(struct xdr_stream *xdr, struct compound_hdr *hdr) |
| 842 | { | 841 | { |
| 843 | __be32 *p; | 842 | __be32 *p; |
| 844 | 843 | ||
| 845 | RESERVE_SPACE(4); | 844 | RESERVE_SPACE(4); |
| 846 | WRITE32(OP_GETFH); | 845 | WRITE32(OP_GETFH); |
| 847 | 846 | hdr->nops++; | |
| 848 | return 0; | ||
| 849 | } | 847 | } |
| 850 | 848 | ||
| 851 | static int encode_link(struct xdr_stream *xdr, const struct qstr *name) | 849 | static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) |
| 852 | { | 850 | { |
| 853 | __be32 *p; | 851 | __be32 *p; |
| 854 | 852 | ||
| @@ -856,8 +854,7 @@ static int encode_link(struct xdr_stream *xdr, const struct qstr *name) | |||
| 856 | WRITE32(OP_LINK); | 854 | WRITE32(OP_LINK); |
| 857 | WRITE32(name->len); | 855 | WRITE32(name->len); |
| 858 | WRITEMEM(name->name, name->len); | 856 | WRITEMEM(name->name, name->len); |
| 859 | 857 | hdr->nops++; | |
| 860 | return 0; | ||
| 861 | } | 858 | } |
| 862 | 859 | ||
| 863 | static inline int nfs4_lock_type(struct file_lock *fl, int block) | 860 | static inline int nfs4_lock_type(struct file_lock *fl, int block) |
| @@ -878,7 +875,7 @@ static inline uint64_t nfs4_lock_length(struct file_lock *fl) | |||
| 878 | * opcode,type,reclaim,offset,length,new_lock_owner = 32 | 875 | * opcode,type,reclaim,offset,length,new_lock_owner = 32 |
| 879 | * open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40 | 876 | * open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40 |
| 880 | */ | 877 | */ |
| 881 | static int encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args) | 878 | static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args, struct compound_hdr *hdr) |
| 882 | { | 879 | { |
| 883 | __be32 *p; | 880 | __be32 *p; |
| 884 | 881 | ||
| @@ -904,11 +901,10 @@ static int encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args) | |||
| 904 | WRITEMEM(args->lock_stateid->data, NFS4_STATEID_SIZE); | 901 | WRITEMEM(args->lock_stateid->data, NFS4_STATEID_SIZE); |
| 905 | WRITE32(args->lock_seqid->sequence->counter); | 902 | WRITE32(args->lock_seqid->sequence->counter); |
| 906 | } | 903 | } |
| 907 | 904 | hdr->nops++; | |
| 908 | return 0; | ||
| 909 | } | 905 | } |
| 910 | 906 | ||
| 911 | static int encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args) | 907 | static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args, struct compound_hdr *hdr) |
| 912 | { | 908 | { |
| 913 | __be32 *p; | 909 | __be32 *p; |
| 914 | 910 | ||
| @@ -921,11 +917,10 @@ static int encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *arg | |||
| 921 | WRITE32(16); | 917 | WRITE32(16); |
| 922 | WRITEMEM("lock id:", 8); | 918 | WRITEMEM("lock id:", 8); |
| 923 | WRITE64(args->lock_owner.id); | 919 | WRITE64(args->lock_owner.id); |
| 924 | 920 | hdr->nops++; | |
| 925 | return 0; | ||
| 926 | } | 921 | } |
| 927 | 922 | ||
| 928 | static int encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args) | 923 | static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args, struct compound_hdr *hdr) |
| 929 | { | 924 | { |
| 930 | __be32 *p; | 925 | __be32 *p; |
| 931 | 926 | ||
| @@ -936,11 +931,10 @@ static int encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *arg | |||
| 936 | WRITEMEM(args->stateid->data, NFS4_STATEID_SIZE); | 931 | WRITEMEM(args->stateid->data, NFS4_STATEID_SIZE); |
| 937 | WRITE64(args->fl->fl_start); | 932 | WRITE64(args->fl->fl_start); |
| 938 | WRITE64(nfs4_lock_length(args->fl)); | 933 | WRITE64(nfs4_lock_length(args->fl)); |
| 939 | 934 | hdr->nops++; | |
| 940 | return 0; | ||
| 941 | } | 935 | } |
| 942 | 936 | ||
| 943 | static int encode_lookup(struct xdr_stream *xdr, const struct qstr *name) | 937 | static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) |
| 944 | { | 938 | { |
| 945 | int len = name->len; | 939 | int len = name->len; |
| 946 | __be32 *p; | 940 | __be32 *p; |
| @@ -949,27 +943,26 @@ static int encode_lookup(struct xdr_stream *xdr, const struct qstr *name) | |||
| 949 | WRITE32(OP_LOOKUP); | 943 | WRITE32(OP_LOOKUP); |
| 950 | WRITE32(len); | 944 | WRITE32(len); |
| 951 | WRITEMEM(name->name, len); | 945 | WRITEMEM(name->name, len); |
| 952 | 946 | hdr->nops++; | |
| 953 | return 0; | ||
| 954 | } | 947 | } |
| 955 | 948 | ||
| 956 | static void encode_share_access(struct xdr_stream *xdr, int open_flags) | 949 | static void encode_share_access(struct xdr_stream *xdr, fmode_t fmode) |
| 957 | { | 950 | { |
| 958 | __be32 *p; | 951 | __be32 *p; |
| 959 | 952 | ||
| 960 | RESERVE_SPACE(8); | 953 | RESERVE_SPACE(8); |
| 961 | switch (open_flags & (FMODE_READ|FMODE_WRITE)) { | 954 | switch (fmode & (FMODE_READ|FMODE_WRITE)) { |
| 962 | case FMODE_READ: | 955 | case FMODE_READ: |
| 963 | WRITE32(NFS4_SHARE_ACCESS_READ); | 956 | WRITE32(NFS4_SHARE_ACCESS_READ); |
| 964 | break; | 957 | break; |
| 965 | case FMODE_WRITE: | 958 | case FMODE_WRITE: |
| 966 | WRITE32(NFS4_SHARE_ACCESS_WRITE); | 959 | WRITE32(NFS4_SHARE_ACCESS_WRITE); |
| 967 | break; | 960 | break; |
| 968 | case FMODE_READ|FMODE_WRITE: | 961 | case FMODE_READ|FMODE_WRITE: |
| 969 | WRITE32(NFS4_SHARE_ACCESS_BOTH); | 962 | WRITE32(NFS4_SHARE_ACCESS_BOTH); |
| 970 | break; | 963 | break; |
| 971 | default: | 964 | default: |
| 972 | BUG(); | 965 | WRITE32(0); |
| 973 | } | 966 | } |
| 974 | WRITE32(0); /* for linux, share_deny = 0 always */ | 967 | WRITE32(0); /* for linux, share_deny = 0 always */ |
| 975 | } | 968 | } |
| @@ -984,7 +977,7 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena | |||
| 984 | RESERVE_SPACE(8); | 977 | RESERVE_SPACE(8); |
| 985 | WRITE32(OP_OPEN); | 978 | WRITE32(OP_OPEN); |
| 986 | WRITE32(arg->seqid->sequence->counter); | 979 | WRITE32(arg->seqid->sequence->counter); |
| 987 | encode_share_access(xdr, arg->open_flags); | 980 | encode_share_access(xdr, arg->fmode); |
| 988 | RESERVE_SPACE(28); | 981 | RESERVE_SPACE(28); |
| 989 | WRITE64(arg->clientid); | 982 | WRITE64(arg->clientid); |
| 990 | WRITE32(16); | 983 | WRITE32(16); |
| @@ -998,13 +991,13 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op | |||
| 998 | 991 | ||
| 999 | RESERVE_SPACE(4); | 992 | RESERVE_SPACE(4); |
| 1000 | switch(arg->open_flags & O_EXCL) { | 993 | switch(arg->open_flags & O_EXCL) { |
| 1001 | case 0: | 994 | case 0: |
| 1002 | WRITE32(NFS4_CREATE_UNCHECKED); | 995 | WRITE32(NFS4_CREATE_UNCHECKED); |
| 1003 | encode_attrs(xdr, arg->u.attrs, arg->server); | 996 | encode_attrs(xdr, arg->u.attrs, arg->server); |
| 1004 | break; | 997 | break; |
| 1005 | default: | 998 | default: |
| 1006 | WRITE32(NFS4_CREATE_EXCLUSIVE); | 999 | WRITE32(NFS4_CREATE_EXCLUSIVE); |
| 1007 | encode_nfs4_verifier(xdr, &arg->u.verifier); | 1000 | encode_nfs4_verifier(xdr, &arg->u.verifier); |
| 1008 | } | 1001 | } |
| 1009 | } | 1002 | } |
| 1010 | 1003 | ||
| @@ -1014,33 +1007,33 @@ static void encode_opentype(struct xdr_stream *xdr, const struct nfs_openargs *a | |||
| 1014 | 1007 | ||
| 1015 | RESERVE_SPACE(4); | 1008 | RESERVE_SPACE(4); |
| 1016 | switch (arg->open_flags & O_CREAT) { | 1009 | switch (arg->open_flags & O_CREAT) { |
| 1017 | case 0: | 1010 | case 0: |
| 1018 | WRITE32(NFS4_OPEN_NOCREATE); | 1011 | WRITE32(NFS4_OPEN_NOCREATE); |
| 1019 | break; | 1012 | break; |
| 1020 | default: | 1013 | default: |
| 1021 | BUG_ON(arg->claim != NFS4_OPEN_CLAIM_NULL); | 1014 | BUG_ON(arg->claim != NFS4_OPEN_CLAIM_NULL); |
| 1022 | WRITE32(NFS4_OPEN_CREATE); | 1015 | WRITE32(NFS4_OPEN_CREATE); |
| 1023 | encode_createmode(xdr, arg); | 1016 | encode_createmode(xdr, arg); |
| 1024 | } | 1017 | } |
| 1025 | } | 1018 | } |
| 1026 | 1019 | ||
| 1027 | static inline void encode_delegation_type(struct xdr_stream *xdr, int delegation_type) | 1020 | static inline void encode_delegation_type(struct xdr_stream *xdr, fmode_t delegation_type) |
| 1028 | { | 1021 | { |
| 1029 | __be32 *p; | 1022 | __be32 *p; |
| 1030 | 1023 | ||
| 1031 | RESERVE_SPACE(4); | 1024 | RESERVE_SPACE(4); |
| 1032 | switch (delegation_type) { | 1025 | switch (delegation_type) { |
| 1033 | case 0: | 1026 | case 0: |
| 1034 | WRITE32(NFS4_OPEN_DELEGATE_NONE); | 1027 | WRITE32(NFS4_OPEN_DELEGATE_NONE); |
| 1035 | break; | 1028 | break; |
| 1036 | case FMODE_READ: | 1029 | case FMODE_READ: |
| 1037 | WRITE32(NFS4_OPEN_DELEGATE_READ); | 1030 | WRITE32(NFS4_OPEN_DELEGATE_READ); |
| 1038 | break; | 1031 | break; |
| 1039 | case FMODE_WRITE|FMODE_READ: | 1032 | case FMODE_WRITE|FMODE_READ: |
| 1040 | WRITE32(NFS4_OPEN_DELEGATE_WRITE); | 1033 | WRITE32(NFS4_OPEN_DELEGATE_WRITE); |
| 1041 | break; | 1034 | break; |
| 1042 | default: | 1035 | default: |
| 1043 | BUG(); | 1036 | BUG(); |
| 1044 | } | 1037 | } |
| 1045 | } | 1038 | } |
| 1046 | 1039 | ||
| @@ -1053,7 +1046,7 @@ static inline void encode_claim_null(struct xdr_stream *xdr, const struct qstr * | |||
| 1053 | encode_string(xdr, name->len, name->name); | 1046 | encode_string(xdr, name->len, name->name); |
| 1054 | } | 1047 | } |
| 1055 | 1048 | ||
| 1056 | static inline void encode_claim_previous(struct xdr_stream *xdr, int type) | 1049 | static inline void encode_claim_previous(struct xdr_stream *xdr, fmode_t type) |
| 1057 | { | 1050 | { |
| 1058 | __be32 *p; | 1051 | __be32 *p; |
| 1059 | 1052 | ||
| @@ -1072,27 +1065,27 @@ static inline void encode_claim_delegate_cur(struct xdr_stream *xdr, const struc | |||
| 1072 | encode_string(xdr, name->len, name->name); | 1065 | encode_string(xdr, name->len, name->name); |
| 1073 | } | 1066 | } |
| 1074 | 1067 | ||
| 1075 | static int encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg) | 1068 | static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg, struct compound_hdr *hdr) |
| 1076 | { | 1069 | { |
| 1077 | encode_openhdr(xdr, arg); | 1070 | encode_openhdr(xdr, arg); |
| 1078 | encode_opentype(xdr, arg); | 1071 | encode_opentype(xdr, arg); |
| 1079 | switch (arg->claim) { | 1072 | switch (arg->claim) { |
| 1080 | case NFS4_OPEN_CLAIM_NULL: | 1073 | case NFS4_OPEN_CLAIM_NULL: |
| 1081 | encode_claim_null(xdr, arg->name); | 1074 | encode_claim_null(xdr, arg->name); |
| 1082 | break; | 1075 | break; |
| 1083 | case NFS4_OPEN_CLAIM_PREVIOUS: | 1076 | case NFS4_OPEN_CLAIM_PREVIOUS: |
| 1084 | encode_claim_previous(xdr, arg->u.delegation_type); | 1077 | encode_claim_previous(xdr, arg->u.delegation_type); |
| 1085 | break; | 1078 | break; |
| 1086 | case NFS4_OPEN_CLAIM_DELEGATE_CUR: | 1079 | case NFS4_OPEN_CLAIM_DELEGATE_CUR: |
| 1087 | encode_claim_delegate_cur(xdr, arg->name, &arg->u.delegation); | 1080 | encode_claim_delegate_cur(xdr, arg->name, &arg->u.delegation); |
| 1088 | break; | 1081 | break; |
| 1089 | default: | 1082 | default: |
| 1090 | BUG(); | 1083 | BUG(); |
| 1091 | } | 1084 | } |
| 1092 | return 0; | 1085 | hdr->nops++; |
| 1093 | } | 1086 | } |
| 1094 | 1087 | ||
| 1095 | static int encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg) | 1088 | static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg, struct compound_hdr *hdr) |
| 1096 | { | 1089 | { |
| 1097 | __be32 *p; | 1090 | __be32 *p; |
| 1098 | 1091 | ||
| @@ -1100,11 +1093,10 @@ static int encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_con | |||
| 1100 | WRITE32(OP_OPEN_CONFIRM); | 1093 | WRITE32(OP_OPEN_CONFIRM); |
| 1101 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); | 1094 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); |
| 1102 | WRITE32(arg->seqid->sequence->counter); | 1095 | WRITE32(arg->seqid->sequence->counter); |
| 1103 | 1096 | hdr->nops++; | |
| 1104 | return 0; | ||
| 1105 | } | 1097 | } |
| 1106 | 1098 | ||
| 1107 | static int encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg) | 1099 | static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr) |
| 1108 | { | 1100 | { |
| 1109 | __be32 *p; | 1101 | __be32 *p; |
| 1110 | 1102 | ||
| @@ -1112,12 +1104,12 @@ static int encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closea | |||
| 1112 | WRITE32(OP_OPEN_DOWNGRADE); | 1104 | WRITE32(OP_OPEN_DOWNGRADE); |
| 1113 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); | 1105 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); |
| 1114 | WRITE32(arg->seqid->sequence->counter); | 1106 | WRITE32(arg->seqid->sequence->counter); |
| 1115 | encode_share_access(xdr, arg->open_flags); | 1107 | encode_share_access(xdr, arg->fmode); |
| 1116 | return 0; | 1108 | hdr->nops++; |
| 1117 | } | 1109 | } |
| 1118 | 1110 | ||
| 1119 | static int | 1111 | static void |
| 1120 | encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh) | 1112 | encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh, struct compound_hdr *hdr) |
| 1121 | { | 1113 | { |
| 1122 | int len = fh->size; | 1114 | int len = fh->size; |
| 1123 | __be32 *p; | 1115 | __be32 *p; |
| @@ -1126,18 +1118,16 @@ encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh) | |||
| 1126 | WRITE32(OP_PUTFH); | 1118 | WRITE32(OP_PUTFH); |
| 1127 | WRITE32(len); | 1119 | WRITE32(len); |
| 1128 | WRITEMEM(fh->data, len); | 1120 | WRITEMEM(fh->data, len); |
| 1129 | 1121 | hdr->nops++; | |
| 1130 | return 0; | ||
| 1131 | } | 1122 | } |
| 1132 | 1123 | ||
| 1133 | static int encode_putrootfh(struct xdr_stream *xdr) | 1124 | static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr) |
| 1134 | { | 1125 | { |
| 1135 | __be32 *p; | 1126 | __be32 *p; |
| 1136 | |||
| 1137 | RESERVE_SPACE(4); | ||
| 1138 | WRITE32(OP_PUTROOTFH); | ||
| 1139 | 1127 | ||
| 1140 | return 0; | 1128 | RESERVE_SPACE(4); |
| 1129 | WRITE32(OP_PUTROOTFH); | ||
| 1130 | hdr->nops++; | ||
| 1141 | } | 1131 | } |
| 1142 | 1132 | ||
| 1143 | static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx) | 1133 | static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx) |
| @@ -1153,7 +1143,7 @@ static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context | |||
| 1153 | WRITEMEM(zero_stateid.data, NFS4_STATEID_SIZE); | 1143 | WRITEMEM(zero_stateid.data, NFS4_STATEID_SIZE); |
| 1154 | } | 1144 | } |
| 1155 | 1145 | ||
| 1156 | static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args) | 1146 | static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, struct compound_hdr *hdr) |
| 1157 | { | 1147 | { |
| 1158 | __be32 *p; | 1148 | __be32 *p; |
| 1159 | 1149 | ||
| @@ -1165,11 +1155,10 @@ static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args) | |||
| 1165 | RESERVE_SPACE(12); | 1155 | RESERVE_SPACE(12); |
| 1166 | WRITE64(args->offset); | 1156 | WRITE64(args->offset); |
| 1167 | WRITE32(args->count); | 1157 | WRITE32(args->count); |
| 1168 | 1158 | hdr->nops++; | |
| 1169 | return 0; | ||
| 1170 | } | 1159 | } |
| 1171 | 1160 | ||
| 1172 | static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req) | 1161 | static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr) |
| 1173 | { | 1162 | { |
| 1174 | uint32_t attrs[2] = { | 1163 | uint32_t attrs[2] = { |
| 1175 | FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID, | 1164 | FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID, |
| @@ -1191,6 +1180,7 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg | |||
| 1191 | attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; | 1180 | attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; |
| 1192 | WRITE32(attrs[0] & readdir->bitmask[0]); | 1181 | WRITE32(attrs[0] & readdir->bitmask[0]); |
| 1193 | WRITE32(attrs[1] & readdir->bitmask[1]); | 1182 | WRITE32(attrs[1] & readdir->bitmask[1]); |
| 1183 | hdr->nops++; | ||
| 1194 | dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n", | 1184 | dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n", |
| 1195 | __func__, | 1185 | __func__, |
| 1196 | (unsigned long long)readdir->cookie, | 1186 | (unsigned long long)readdir->cookie, |
| @@ -1198,21 +1188,18 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg | |||
| 1198 | ((u32 *)readdir->verifier.data)[1], | 1188 | ((u32 *)readdir->verifier.data)[1], |
| 1199 | attrs[0] & readdir->bitmask[0], | 1189 | attrs[0] & readdir->bitmask[0], |
| 1200 | attrs[1] & readdir->bitmask[1]); | 1190 | attrs[1] & readdir->bitmask[1]); |
| 1201 | |||
| 1202 | return 0; | ||
| 1203 | } | 1191 | } |
| 1204 | 1192 | ||
| 1205 | static int encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req) | 1193 | static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req, struct compound_hdr *hdr) |
| 1206 | { | 1194 | { |
| 1207 | __be32 *p; | 1195 | __be32 *p; |
| 1208 | 1196 | ||
| 1209 | RESERVE_SPACE(4); | 1197 | RESERVE_SPACE(4); |
| 1210 | WRITE32(OP_READLINK); | 1198 | WRITE32(OP_READLINK); |
| 1211 | 1199 | hdr->nops++; | |
| 1212 | return 0; | ||
| 1213 | } | 1200 | } |
| 1214 | 1201 | ||
| 1215 | static int encode_remove(struct xdr_stream *xdr, const struct qstr *name) | 1202 | static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) |
| 1216 | { | 1203 | { |
| 1217 | __be32 *p; | 1204 | __be32 *p; |
| 1218 | 1205 | ||
| @@ -1220,11 +1207,10 @@ static int encode_remove(struct xdr_stream *xdr, const struct qstr *name) | |||
| 1220 | WRITE32(OP_REMOVE); | 1207 | WRITE32(OP_REMOVE); |
| 1221 | WRITE32(name->len); | 1208 | WRITE32(name->len); |
| 1222 | WRITEMEM(name->name, name->len); | 1209 | WRITEMEM(name->name, name->len); |
| 1223 | 1210 | hdr->nops++; | |
| 1224 | return 0; | ||
| 1225 | } | 1211 | } |
| 1226 | 1212 | ||
| 1227 | static int encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname) | 1213 | static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname, struct compound_hdr *hdr) |
| 1228 | { | 1214 | { |
| 1229 | __be32 *p; | 1215 | __be32 *p; |
| 1230 | 1216 | ||
| @@ -1232,38 +1218,35 @@ static int encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, con | |||
| 1232 | WRITE32(OP_RENAME); | 1218 | WRITE32(OP_RENAME); |
| 1233 | WRITE32(oldname->len); | 1219 | WRITE32(oldname->len); |
| 1234 | WRITEMEM(oldname->name, oldname->len); | 1220 | WRITEMEM(oldname->name, oldname->len); |
| 1235 | 1221 | ||
| 1236 | RESERVE_SPACE(4 + newname->len); | 1222 | RESERVE_SPACE(4 + newname->len); |
| 1237 | WRITE32(newname->len); | 1223 | WRITE32(newname->len); |
| 1238 | WRITEMEM(newname->name, newname->len); | 1224 | WRITEMEM(newname->name, newname->len); |
| 1239 | 1225 | hdr->nops++; | |
| 1240 | return 0; | ||
| 1241 | } | 1226 | } |
| 1242 | 1227 | ||
| 1243 | static int encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid) | 1228 | static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid, struct compound_hdr *hdr) |
| 1244 | { | 1229 | { |
| 1245 | __be32 *p; | 1230 | __be32 *p; |
| 1246 | 1231 | ||
| 1247 | RESERVE_SPACE(12); | 1232 | RESERVE_SPACE(12); |
| 1248 | WRITE32(OP_RENEW); | 1233 | WRITE32(OP_RENEW); |
| 1249 | WRITE64(client_stateid->cl_clientid); | 1234 | WRITE64(client_stateid->cl_clientid); |
| 1250 | 1235 | hdr->nops++; | |
| 1251 | return 0; | ||
| 1252 | } | 1236 | } |
| 1253 | 1237 | ||
| 1254 | static int | 1238 | static void |
| 1255 | encode_restorefh(struct xdr_stream *xdr) | 1239 | encode_restorefh(struct xdr_stream *xdr, struct compound_hdr *hdr) |
| 1256 | { | 1240 | { |
| 1257 | __be32 *p; | 1241 | __be32 *p; |
| 1258 | 1242 | ||
| 1259 | RESERVE_SPACE(4); | 1243 | RESERVE_SPACE(4); |
| 1260 | WRITE32(OP_RESTOREFH); | 1244 | WRITE32(OP_RESTOREFH); |
| 1261 | 1245 | hdr->nops++; | |
| 1262 | return 0; | ||
| 1263 | } | 1246 | } |
| 1264 | 1247 | ||
| 1265 | static int | 1248 | static int |
| 1266 | encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg) | 1249 | encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compound_hdr *hdr) |
| 1267 | { | 1250 | { |
| 1268 | __be32 *p; | 1251 | __be32 *p; |
| 1269 | 1252 | ||
| @@ -1278,36 +1261,32 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg) | |||
| 1278 | RESERVE_SPACE(4); | 1261 | RESERVE_SPACE(4); |
| 1279 | WRITE32(arg->acl_len); | 1262 | WRITE32(arg->acl_len); |
| 1280 | xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len); | 1263 | xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len); |
| 1264 | hdr->nops++; | ||
| 1281 | return 0; | 1265 | return 0; |
| 1282 | } | 1266 | } |
| 1283 | 1267 | ||
| 1284 | static int | 1268 | static void |
| 1285 | encode_savefh(struct xdr_stream *xdr) | 1269 | encode_savefh(struct xdr_stream *xdr, struct compound_hdr *hdr) |
| 1286 | { | 1270 | { |
| 1287 | __be32 *p; | 1271 | __be32 *p; |
| 1288 | 1272 | ||
| 1289 | RESERVE_SPACE(4); | 1273 | RESERVE_SPACE(4); |
| 1290 | WRITE32(OP_SAVEFH); | 1274 | WRITE32(OP_SAVEFH); |
| 1291 | 1275 | hdr->nops++; | |
| 1292 | return 0; | ||
| 1293 | } | 1276 | } |
| 1294 | 1277 | ||
| 1295 | static int encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server) | 1278 | static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server, struct compound_hdr *hdr) |
| 1296 | { | 1279 | { |
| 1297 | int status; | ||
| 1298 | __be32 *p; | 1280 | __be32 *p; |
| 1299 | |||
| 1300 | RESERVE_SPACE(4+NFS4_STATEID_SIZE); | ||
| 1301 | WRITE32(OP_SETATTR); | ||
| 1302 | WRITEMEM(arg->stateid.data, NFS4_STATEID_SIZE); | ||
| 1303 | 1281 | ||
| 1304 | if ((status = encode_attrs(xdr, arg->iap, server))) | 1282 | RESERVE_SPACE(4+NFS4_STATEID_SIZE); |
| 1305 | return status; | 1283 | WRITE32(OP_SETATTR); |
| 1306 | 1284 | WRITEMEM(arg->stateid.data, NFS4_STATEID_SIZE); | |
| 1307 | return 0; | 1285 | hdr->nops++; |
| 1286 | encode_attrs(xdr, arg->iap, server); | ||
| 1308 | } | 1287 | } |
| 1309 | 1288 | ||
| 1310 | static int encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid) | 1289 | static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid, struct compound_hdr *hdr) |
| 1311 | { | 1290 | { |
| 1312 | __be32 *p; | 1291 | __be32 *p; |
| 1313 | 1292 | ||
| @@ -1322,23 +1301,21 @@ static int encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclien | |||
| 1322 | encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr); | 1301 | encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr); |
| 1323 | RESERVE_SPACE(4); | 1302 | RESERVE_SPACE(4); |
| 1324 | WRITE32(setclientid->sc_cb_ident); | 1303 | WRITE32(setclientid->sc_cb_ident); |
| 1325 | 1304 | hdr->nops++; | |
| 1326 | return 0; | ||
| 1327 | } | 1305 | } |
| 1328 | 1306 | ||
| 1329 | static int encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state) | 1307 | static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state, struct compound_hdr *hdr) |
| 1330 | { | 1308 | { |
| 1331 | __be32 *p; | 1309 | __be32 *p; |
| 1332 | |||
| 1333 | RESERVE_SPACE(12 + NFS4_VERIFIER_SIZE); | ||
| 1334 | WRITE32(OP_SETCLIENTID_CONFIRM); | ||
| 1335 | WRITE64(client_state->cl_clientid); | ||
| 1336 | WRITEMEM(client_state->cl_confirm.data, NFS4_VERIFIER_SIZE); | ||
| 1337 | 1310 | ||
| 1338 | return 0; | 1311 | RESERVE_SPACE(12 + NFS4_VERIFIER_SIZE); |
| 1312 | WRITE32(OP_SETCLIENTID_CONFIRM); | ||
| 1313 | WRITE64(client_state->cl_clientid); | ||
| 1314 | WRITEMEM(client_state->cl_confirm.data, NFS4_VERIFIER_SIZE); | ||
| 1315 | hdr->nops++; | ||
| 1339 | } | 1316 | } |
| 1340 | 1317 | ||
| 1341 | static int encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args) | 1318 | static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr) |
| 1342 | { | 1319 | { |
| 1343 | __be32 *p; | 1320 | __be32 *p; |
| 1344 | 1321 | ||
| @@ -1353,11 +1330,10 @@ static int encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args | |||
| 1353 | WRITE32(args->count); | 1330 | WRITE32(args->count); |
| 1354 | 1331 | ||
| 1355 | xdr_write_pages(xdr, args->pages, args->pgbase, args->count); | 1332 | xdr_write_pages(xdr, args->pages, args->pgbase, args->count); |
| 1356 | 1333 | hdr->nops++; | |
| 1357 | return 0; | ||
| 1358 | } | 1334 | } |
| 1359 | 1335 | ||
| 1360 | static int encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid) | 1336 | static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid, struct compound_hdr *hdr) |
| 1361 | { | 1337 | { |
| 1362 | __be32 *p; | 1338 | __be32 *p; |
| 1363 | 1339 | ||
| @@ -1365,8 +1341,7 @@ static int encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *statei | |||
| 1365 | 1341 | ||
| 1366 | WRITE32(OP_DELEGRETURN); | 1342 | WRITE32(OP_DELEGRETURN); |
| 1367 | WRITEMEM(stateid->data, NFS4_STATEID_SIZE); | 1343 | WRITEMEM(stateid->data, NFS4_STATEID_SIZE); |
| 1368 | return 0; | 1344 | hdr->nops++; |
| 1369 | |||
| 1370 | } | 1345 | } |
| 1371 | /* | 1346 | /* |
| 1372 | * END OF "GENERIC" ENCODE ROUTINES. | 1347 | * END OF "GENERIC" ENCODE ROUTINES. |
| @@ -1379,21 +1354,16 @@ static int nfs4_xdr_enc_access(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
| 1379 | { | 1354 | { |
| 1380 | struct xdr_stream xdr; | 1355 | struct xdr_stream xdr; |
| 1381 | struct compound_hdr hdr = { | 1356 | struct compound_hdr hdr = { |
| 1382 | .nops = 3, | 1357 | .nops = 0, |
| 1383 | }; | 1358 | }; |
| 1384 | int status; | ||
| 1385 | 1359 | ||
| 1386 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1360 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1387 | encode_compound_hdr(&xdr, &hdr); | 1361 | encode_compound_hdr(&xdr, &hdr); |
| 1388 | status = encode_putfh(&xdr, args->fh); | 1362 | encode_putfh(&xdr, args->fh, &hdr); |
| 1389 | if (status != 0) | 1363 | encode_access(&xdr, args->access, &hdr); |
| 1390 | goto out; | 1364 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| 1391 | status = encode_access(&xdr, args->access); | 1365 | encode_nops(&hdr); |
| 1392 | if (status != 0) | 1366 | return 0; |
| 1393 | goto out; | ||
| 1394 | status = encode_getfattr(&xdr, args->bitmask); | ||
| 1395 | out: | ||
| 1396 | return status; | ||
| 1397 | } | 1367 | } |
| 1398 | 1368 | ||
| 1399 | /* | 1369 | /* |
| @@ -1403,21 +1373,17 @@ static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
| 1403 | { | 1373 | { |
| 1404 | struct xdr_stream xdr; | 1374 | struct xdr_stream xdr; |
| 1405 | struct compound_hdr hdr = { | 1375 | struct compound_hdr hdr = { |
| 1406 | .nops = 4, | 1376 | .nops = 0, |
| 1407 | }; | 1377 | }; |
| 1408 | int status; | ||
| 1409 | 1378 | ||
| 1410 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1379 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1411 | encode_compound_hdr(&xdr, &hdr); | 1380 | encode_compound_hdr(&xdr, &hdr); |
| 1412 | if ((status = encode_putfh(&xdr, args->dir_fh)) != 0) | 1381 | encode_putfh(&xdr, args->dir_fh, &hdr); |
| 1413 | goto out; | 1382 | encode_lookup(&xdr, args->name, &hdr); |
| 1414 | if ((status = encode_lookup(&xdr, args->name)) != 0) | 1383 | encode_getfh(&xdr, &hdr); |
| 1415 | goto out; | 1384 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| 1416 | if ((status = encode_getfh(&xdr)) != 0) | 1385 | encode_nops(&hdr); |
| 1417 | goto out; | 1386 | return 0; |
| 1418 | status = encode_getfattr(&xdr, args->bitmask); | ||
| 1419 | out: | ||
| 1420 | return status; | ||
| 1421 | } | 1387 | } |
| 1422 | 1388 | ||
| 1423 | /* | 1389 | /* |
| @@ -1427,18 +1393,16 @@ static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, __be32 *p, const struc | |||
| 1427 | { | 1393 | { |
| 1428 | struct xdr_stream xdr; | 1394 | struct xdr_stream xdr; |
| 1429 | struct compound_hdr hdr = { | 1395 | struct compound_hdr hdr = { |
| 1430 | .nops = 3, | 1396 | .nops = 0, |
| 1431 | }; | 1397 | }; |
| 1432 | int status; | ||
| 1433 | 1398 | ||
| 1434 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1399 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1435 | encode_compound_hdr(&xdr, &hdr); | 1400 | encode_compound_hdr(&xdr, &hdr); |
| 1436 | if ((status = encode_putrootfh(&xdr)) != 0) | 1401 | encode_putrootfh(&xdr, &hdr); |
| 1437 | goto out; | 1402 | encode_getfh(&xdr, &hdr); |
| 1438 | if ((status = encode_getfh(&xdr)) == 0) | 1403 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| 1439 | status = encode_getfattr(&xdr, args->bitmask); | 1404 | encode_nops(&hdr); |
| 1440 | out: | 1405 | return 0; |
| 1441 | return status; | ||
| 1442 | } | 1406 | } |
| 1443 | 1407 | ||
| 1444 | /* | 1408 | /* |
| @@ -1448,19 +1412,16 @@ static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
| 1448 | { | 1412 | { |
| 1449 | struct xdr_stream xdr; | 1413 | struct xdr_stream xdr; |
| 1450 | struct compound_hdr hdr = { | 1414 | struct compound_hdr hdr = { |
| 1451 | .nops = 3, | 1415 | .nops = 0, |
| 1452 | }; | 1416 | }; |
| 1453 | int status; | ||
| 1454 | 1417 | ||
| 1455 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1418 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1456 | encode_compound_hdr(&xdr, &hdr); | 1419 | encode_compound_hdr(&xdr, &hdr); |
| 1457 | if ((status = encode_putfh(&xdr, args->fh)) != 0) | 1420 | encode_putfh(&xdr, args->fh, &hdr); |
| 1458 | goto out; | 1421 | encode_remove(&xdr, &args->name, &hdr); |
| 1459 | if ((status = encode_remove(&xdr, &args->name)) != 0) | 1422 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| 1460 | goto out; | 1423 | encode_nops(&hdr); |
| 1461 | status = encode_getfattr(&xdr, args->bitmask); | 1424 | return 0; |
| 1462 | out: | ||
| 1463 | return status; | ||
| 1464 | } | 1425 | } |
| 1465 | 1426 | ||
| 1466 | /* | 1427 | /* |
| @@ -1470,27 +1431,20 @@ static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
| 1470 | { | 1431 | { |
| 1471 | struct xdr_stream xdr; | 1432 | struct xdr_stream xdr; |
| 1472 | struct compound_hdr hdr = { | 1433 | struct compound_hdr hdr = { |
| 1473 | .nops = 7, | 1434 | .nops = 0, |
| 1474 | }; | 1435 | }; |
| 1475 | int status; | ||
| 1476 | 1436 | ||
| 1477 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1437 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1478 | encode_compound_hdr(&xdr, &hdr); | 1438 | encode_compound_hdr(&xdr, &hdr); |
| 1479 | if ((status = encode_putfh(&xdr, args->old_dir)) != 0) | 1439 | encode_putfh(&xdr, args->old_dir, &hdr); |
| 1480 | goto out; | 1440 | encode_savefh(&xdr, &hdr); |
| 1481 | if ((status = encode_savefh(&xdr)) != 0) | 1441 | encode_putfh(&xdr, args->new_dir, &hdr); |
| 1482 | goto out; | 1442 | encode_rename(&xdr, args->old_name, args->new_name, &hdr); |
| 1483 | if ((status = encode_putfh(&xdr, args->new_dir)) != 0) | 1443 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| 1484 | goto out; | 1444 | encode_restorefh(&xdr, &hdr); |
| 1485 | if ((status = encode_rename(&xdr, args->old_name, args->new_name)) != 0) | 1445 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| 1486 | goto out; | 1446 | encode_nops(&hdr); |
| 1487 | if ((status = encode_getfattr(&xdr, args->bitmask)) != 0) | 1447 | return 0; |
| 1488 | goto out; | ||
| 1489 | if ((status = encode_restorefh(&xdr)) != 0) | ||
| 1490 | goto out; | ||
| 1491 | status = encode_getfattr(&xdr, args->bitmask); | ||
| 1492 | out: | ||
| 1493 | return status; | ||
| 1494 | } | 1448 | } |
| 1495 | 1449 | ||
| 1496 | /* | 1450 | /* |
| @@ -1500,27 +1454,20 @@ static int nfs4_xdr_enc_link(struct rpc_rqst *req, __be32 *p, const struct nfs4_ | |||
| 1500 | { | 1454 | { |
| 1501 | struct xdr_stream xdr; | 1455 | struct xdr_stream xdr; |
| 1502 | struct compound_hdr hdr = { | 1456 | struct compound_hdr hdr = { |
| 1503 | .nops = 7, | 1457 | .nops = 0, |
| 1504 | }; | 1458 | }; |
| 1505 | int status; | ||
| 1506 | 1459 | ||
| 1507 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1460 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1508 | encode_compound_hdr(&xdr, &hdr); | 1461 | encode_compound_hdr(&xdr, &hdr); |
| 1509 | if ((status = encode_putfh(&xdr, args->fh)) != 0) | 1462 | encode_putfh(&xdr, args->fh, &hdr); |
| 1510 | goto out; | 1463 | encode_savefh(&xdr, &hdr); |
| 1511 | if ((status = encode_savefh(&xdr)) != 0) | 1464 | encode_putfh(&xdr, args->dir_fh, &hdr); |
| 1512 | goto out; | 1465 | encode_link(&xdr, args->name, &hdr); |
| 1513 | if ((status = encode_putfh(&xdr, args->dir_fh)) != 0) | 1466 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| 1514 | goto out; | 1467 | encode_restorefh(&xdr, &hdr); |
| 1515 | if ((status = encode_link(&xdr, args->name)) != 0) | 1468 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| 1516 | goto out; | 1469 | encode_nops(&hdr); |
| 1517 | if ((status = encode_getfattr(&xdr, args->bitmask)) != 0) | 1470 | return 0; |
| 1518 | goto out; | ||
| 1519 | if ((status = encode_restorefh(&xdr)) != 0) | ||
| 1520 | goto out; | ||
| 1521 | status = encode_getfattr(&xdr, args->bitmask); | ||
| 1522 | out: | ||
| 1523 | return status; | ||
| 1524 | } | 1471 | } |
| 1525 | 1472 | ||
| 1526 | /* | 1473 | /* |
| @@ -1530,27 +1477,20 @@ static int nfs4_xdr_enc_create(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
| 1530 | { | 1477 | { |
| 1531 | struct xdr_stream xdr; | 1478 | struct xdr_stream xdr; |
| 1532 | struct compound_hdr hdr = { | 1479 | struct compound_hdr hdr = { |
| 1533 | .nops = 7, | 1480 | .nops = 0, |
| 1534 | }; | 1481 | }; |
| 1535 | int status; | ||
| 1536 | 1482 | ||
| 1537 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1483 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1538 | encode_compound_hdr(&xdr, &hdr); | 1484 | encode_compound_hdr(&xdr, &hdr); |
| 1539 | if ((status = encode_putfh(&xdr, args->dir_fh)) != 0) | 1485 | encode_putfh(&xdr, args->dir_fh, &hdr); |
| 1540 | goto out; | 1486 | encode_savefh(&xdr, &hdr); |
| 1541 | if ((status = encode_savefh(&xdr)) != 0) | 1487 | encode_create(&xdr, args, &hdr); |
| 1542 | goto out; | 1488 | encode_getfh(&xdr, &hdr); |
| 1543 | if ((status = encode_create(&xdr, args)) != 0) | 1489 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| 1544 | goto out; | 1490 | encode_restorefh(&xdr, &hdr); |
| 1545 | if ((status = encode_getfh(&xdr)) != 0) | 1491 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| 1546 | goto out; | 1492 | encode_nops(&hdr); |
| 1547 | if ((status = encode_getfattr(&xdr, args->bitmask)) != 0) | 1493 | return 0; |
| 1548 | goto out; | ||
| 1549 | if ((status = encode_restorefh(&xdr)) != 0) | ||
| 1550 | goto out; | ||
| 1551 | status = encode_getfattr(&xdr, args->bitmask); | ||
| 1552 | out: | ||
| 1553 | return status; | ||
| 1554 | } | 1494 | } |
| 1555 | 1495 | ||
| 1556 | /* | 1496 | /* |
| @@ -1568,15 +1508,15 @@ static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, __be32 *p, const struct nf | |||
| 1568 | { | 1508 | { |
| 1569 | struct xdr_stream xdr; | 1509 | struct xdr_stream xdr; |
| 1570 | struct compound_hdr hdr = { | 1510 | struct compound_hdr hdr = { |
| 1571 | .nops = 2, | 1511 | .nops = 0, |
| 1572 | }; | 1512 | }; |
| 1573 | int status; | ||
| 1574 | 1513 | ||
| 1575 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1514 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1576 | encode_compound_hdr(&xdr, &hdr); | 1515 | encode_compound_hdr(&xdr, &hdr); |
| 1577 | if ((status = encode_putfh(&xdr, args->fh)) == 0) | 1516 | encode_putfh(&xdr, args->fh, &hdr); |
| 1578 | status = encode_getfattr(&xdr, args->bitmask); | 1517 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| 1579 | return status; | 1518 | encode_nops(&hdr); |
| 1519 | return 0; | ||
| 1580 | } | 1520 | } |
| 1581 | 1521 | ||
| 1582 | /* | 1522 | /* |
| @@ -1584,23 +1524,18 @@ static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, __be32 *p, const struct nf | |||
| 1584 | */ | 1524 | */ |
| 1585 | static int nfs4_xdr_enc_close(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args) | 1525 | static int nfs4_xdr_enc_close(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args) |
| 1586 | { | 1526 | { |
| 1587 | struct xdr_stream xdr; | 1527 | struct xdr_stream xdr; |
| 1588 | struct compound_hdr hdr = { | 1528 | struct compound_hdr hdr = { |
| 1589 | .nops = 3, | 1529 | .nops = 0, |
| 1590 | }; | 1530 | }; |
| 1591 | int status; | 1531 | |
| 1592 | 1532 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | |
| 1593 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1533 | encode_compound_hdr(&xdr, &hdr); |
| 1594 | encode_compound_hdr(&xdr, &hdr); | 1534 | encode_putfh(&xdr, args->fh, &hdr); |
| 1595 | status = encode_putfh(&xdr, args->fh); | 1535 | encode_close(&xdr, args, &hdr); |
| 1596 | if(status) | 1536 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| 1597 | goto out; | 1537 | encode_nops(&hdr); |
| 1598 | status = encode_close(&xdr, args); | 1538 | return 0; |
| 1599 | if (status != 0) | ||
| 1600 | goto out; | ||
| 1601 | status = encode_getfattr(&xdr, args->bitmask); | ||
| 1602 | out: | ||
| 1603 | return status; | ||
| 1604 | } | 1539 | } |
| 1605 | 1540 | ||
| 1606 | /* | 1541 | /* |
| @@ -1610,33 +1545,20 @@ static int nfs4_xdr_enc_open(struct rpc_rqst *req, __be32 *p, struct nfs_openarg | |||
| 1610 | { | 1545 | { |
| 1611 | struct xdr_stream xdr; | 1546 | struct xdr_stream xdr; |
| 1612 | struct compound_hdr hdr = { | 1547 | struct compound_hdr hdr = { |
| 1613 | .nops = 7, | 1548 | .nops = 0, |
| 1614 | }; | 1549 | }; |
| 1615 | int status; | ||
| 1616 | 1550 | ||
| 1617 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1551 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1618 | encode_compound_hdr(&xdr, &hdr); | 1552 | encode_compound_hdr(&xdr, &hdr); |
| 1619 | status = encode_putfh(&xdr, args->fh); | 1553 | encode_putfh(&xdr, args->fh, &hdr); |
| 1620 | if (status) | 1554 | encode_savefh(&xdr, &hdr); |
| 1621 | goto out; | 1555 | encode_open(&xdr, args, &hdr); |
| 1622 | status = encode_savefh(&xdr); | 1556 | encode_getfh(&xdr, &hdr); |
| 1623 | if (status) | 1557 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| 1624 | goto out; | 1558 | encode_restorefh(&xdr, &hdr); |
| 1625 | status = encode_open(&xdr, args); | 1559 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| 1626 | if (status) | 1560 | encode_nops(&hdr); |
| 1627 | goto out; | 1561 | return 0; |
| 1628 | status = encode_getfh(&xdr); | ||
| 1629 | if (status) | ||
| 1630 | goto out; | ||
| 1631 | status = encode_getfattr(&xdr, args->bitmask); | ||
| 1632 | if (status) | ||
| 1633 | goto out; | ||
| 1634 | status = encode_restorefh(&xdr); | ||
| 1635 | if (status) | ||
| 1636 | goto out; | ||
| 1637 | status = encode_getfattr(&xdr, args->bitmask); | ||
| 1638 | out: | ||
| 1639 | return status; | ||
| 1640 | } | 1562 | } |
| 1641 | 1563 | ||
| 1642 | /* | 1564 | /* |
| @@ -1646,18 +1568,15 @@ static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, __be32 *p, struct nfs | |||
| 1646 | { | 1568 | { |
| 1647 | struct xdr_stream xdr; | 1569 | struct xdr_stream xdr; |
| 1648 | struct compound_hdr hdr = { | 1570 | struct compound_hdr hdr = { |
| 1649 | .nops = 2, | 1571 | .nops = 0, |
| 1650 | }; | 1572 | }; |
| 1651 | int status; | ||
| 1652 | 1573 | ||
| 1653 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1574 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1654 | encode_compound_hdr(&xdr, &hdr); | 1575 | encode_compound_hdr(&xdr, &hdr); |
| 1655 | status = encode_putfh(&xdr, args->fh); | 1576 | encode_putfh(&xdr, args->fh, &hdr); |
| 1656 | if(status) | 1577 | encode_open_confirm(&xdr, args, &hdr); |
| 1657 | goto out; | 1578 | encode_nops(&hdr); |
| 1658 | status = encode_open_confirm(&xdr, args); | 1579 | return 0; |
| 1659 | out: | ||
| 1660 | return status; | ||
| 1661 | } | 1580 | } |
| 1662 | 1581 | ||
| 1663 | /* | 1582 | /* |
| @@ -1667,21 +1586,16 @@ static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, __be32 *p, struct nfs_ | |||
| 1667 | { | 1586 | { |
| 1668 | struct xdr_stream xdr; | 1587 | struct xdr_stream xdr; |
| 1669 | struct compound_hdr hdr = { | 1588 | struct compound_hdr hdr = { |
| 1670 | .nops = 3, | 1589 | .nops = 0, |
| 1671 | }; | 1590 | }; |
| 1672 | int status; | ||
| 1673 | 1591 | ||
| 1674 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1592 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1675 | encode_compound_hdr(&xdr, &hdr); | 1593 | encode_compound_hdr(&xdr, &hdr); |
| 1676 | status = encode_putfh(&xdr, args->fh); | 1594 | encode_putfh(&xdr, args->fh, &hdr); |
| 1677 | if (status) | 1595 | encode_open(&xdr, args, &hdr); |
| 1678 | goto out; | 1596 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| 1679 | status = encode_open(&xdr, args); | 1597 | encode_nops(&hdr); |
| 1680 | if (status) | 1598 | return 0; |
| 1681 | goto out; | ||
| 1682 | status = encode_getfattr(&xdr, args->bitmask); | ||
| 1683 | out: | ||
| 1684 | return status; | ||
| 1685 | } | 1599 | } |
| 1686 | 1600 | ||
| 1687 | /* | 1601 | /* |
| @@ -1691,21 +1605,16 @@ static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, __be32 *p, struct n | |||
| 1691 | { | 1605 | { |
| 1692 | struct xdr_stream xdr; | 1606 | struct xdr_stream xdr; |
| 1693 | struct compound_hdr hdr = { | 1607 | struct compound_hdr hdr = { |
| 1694 | .nops = 3, | 1608 | .nops = 0, |
| 1695 | }; | 1609 | }; |
| 1696 | int status; | ||
| 1697 | 1610 | ||
| 1698 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1611 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1699 | encode_compound_hdr(&xdr, &hdr); | 1612 | encode_compound_hdr(&xdr, &hdr); |
| 1700 | status = encode_putfh(&xdr, args->fh); | 1613 | encode_putfh(&xdr, args->fh, &hdr); |
| 1701 | if (status) | 1614 | encode_open_downgrade(&xdr, args, &hdr); |
| 1702 | goto out; | 1615 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| 1703 | status = encode_open_downgrade(&xdr, args); | 1616 | encode_nops(&hdr); |
| 1704 | if (status != 0) | 1617 | return 0; |
| 1705 | goto out; | ||
| 1706 | status = encode_getfattr(&xdr, args->bitmask); | ||
| 1707 | out: | ||
| 1708 | return status; | ||
| 1709 | } | 1618 | } |
| 1710 | 1619 | ||
| 1711 | /* | 1620 | /* |
| @@ -1715,18 +1624,15 @@ static int nfs4_xdr_enc_lock(struct rpc_rqst *req, __be32 *p, struct nfs_lock_ar | |||
| 1715 | { | 1624 | { |
| 1716 | struct xdr_stream xdr; | 1625 | struct xdr_stream xdr; |
| 1717 | struct compound_hdr hdr = { | 1626 | struct compound_hdr hdr = { |
| 1718 | .nops = 2, | 1627 | .nops = 0, |
| 1719 | }; | 1628 | }; |
| 1720 | int status; | ||
| 1721 | 1629 | ||
| 1722 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1630 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1723 | encode_compound_hdr(&xdr, &hdr); | 1631 | encode_compound_hdr(&xdr, &hdr); |
| 1724 | status = encode_putfh(&xdr, args->fh); | 1632 | encode_putfh(&xdr, args->fh, &hdr); |
| 1725 | if(status) | 1633 | encode_lock(&xdr, args, &hdr); |
| 1726 | goto out; | 1634 | encode_nops(&hdr); |
| 1727 | status = encode_lock(&xdr, args); | 1635 | return 0; |
| 1728 | out: | ||
| 1729 | return status; | ||
| 1730 | } | 1636 | } |
| 1731 | 1637 | ||
| 1732 | /* | 1638 | /* |
| @@ -1736,18 +1642,15 @@ static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, __be32 *p, struct nfs_lockt_ | |||
| 1736 | { | 1642 | { |
| 1737 | struct xdr_stream xdr; | 1643 | struct xdr_stream xdr; |
| 1738 | struct compound_hdr hdr = { | 1644 | struct compound_hdr hdr = { |
| 1739 | .nops = 2, | 1645 | .nops = 0, |
| 1740 | }; | 1646 | }; |
| 1741 | int status; | ||
| 1742 | 1647 | ||
| 1743 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1648 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1744 | encode_compound_hdr(&xdr, &hdr); | 1649 | encode_compound_hdr(&xdr, &hdr); |
| 1745 | status = encode_putfh(&xdr, args->fh); | 1650 | encode_putfh(&xdr, args->fh, &hdr); |
| 1746 | if(status) | 1651 | encode_lockt(&xdr, args, &hdr); |
| 1747 | goto out; | 1652 | encode_nops(&hdr); |
| 1748 | status = encode_lockt(&xdr, args); | 1653 | return 0; |
| 1749 | out: | ||
| 1750 | return status; | ||
| 1751 | } | 1654 | } |
| 1752 | 1655 | ||
| 1753 | /* | 1656 | /* |
| @@ -1757,18 +1660,15 @@ static int nfs4_xdr_enc_locku(struct rpc_rqst *req, __be32 *p, struct nfs_locku_ | |||
| 1757 | { | 1660 | { |
| 1758 | struct xdr_stream xdr; | 1661 | struct xdr_stream xdr; |
| 1759 | struct compound_hdr hdr = { | 1662 | struct compound_hdr hdr = { |
| 1760 | .nops = 2, | 1663 | .nops = 0, |
| 1761 | }; | 1664 | }; |
| 1762 | int status; | ||
| 1763 | 1665 | ||
| 1764 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1666 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1765 | encode_compound_hdr(&xdr, &hdr); | 1667 | encode_compound_hdr(&xdr, &hdr); |
| 1766 | status = encode_putfh(&xdr, args->fh); | 1668 | encode_putfh(&xdr, args->fh, &hdr); |
| 1767 | if(status) | 1669 | encode_locku(&xdr, args, &hdr); |
| 1768 | goto out; | 1670 | encode_nops(&hdr); |
| 1769 | status = encode_locku(&xdr, args); | 1671 | return 0; |
| 1770 | out: | ||
| 1771 | return status; | ||
| 1772 | } | 1672 | } |
| 1773 | 1673 | ||
| 1774 | /* | 1674 | /* |
| @@ -1778,18 +1678,15 @@ static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct n | |||
| 1778 | { | 1678 | { |
| 1779 | struct xdr_stream xdr; | 1679 | struct xdr_stream xdr; |
| 1780 | struct compound_hdr hdr = { | 1680 | struct compound_hdr hdr = { |
| 1781 | .nops = 2, | 1681 | .nops = 0, |
| 1782 | }; | 1682 | }; |
| 1783 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | 1683 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; |
| 1784 | unsigned int replen; | 1684 | unsigned int replen; |
| 1785 | int status; | ||
| 1786 | 1685 | ||
| 1787 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1686 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1788 | encode_compound_hdr(&xdr, &hdr); | 1687 | encode_compound_hdr(&xdr, &hdr); |
| 1789 | status = encode_putfh(&xdr, args->fh); | 1688 | encode_putfh(&xdr, args->fh, &hdr); |
| 1790 | if(status) | 1689 | encode_readlink(&xdr, args, req, &hdr); |
| 1791 | goto out; | ||
| 1792 | status = encode_readlink(&xdr, args, req); | ||
| 1793 | 1690 | ||
| 1794 | /* set up reply kvec | 1691 | /* set up reply kvec |
| 1795 | * toplevel_status + taglen + rescount + OP_PUTFH + status | 1692 | * toplevel_status + taglen + rescount + OP_PUTFH + status |
| @@ -1798,9 +1695,8 @@ static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct n | |||
| 1798 | replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_readlink_sz) << 2; | 1695 | replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_readlink_sz) << 2; |
| 1799 | xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, | 1696 | xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, |
| 1800 | args->pgbase, args->pglen); | 1697 | args->pgbase, args->pglen); |
| 1801 | 1698 | encode_nops(&hdr); | |
| 1802 | out: | 1699 | return 0; |
| 1803 | return status; | ||
| 1804 | } | 1700 | } |
| 1805 | 1701 | ||
| 1806 | /* | 1702 | /* |
| @@ -1810,18 +1706,15 @@ static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nf | |||
| 1810 | { | 1706 | { |
| 1811 | struct xdr_stream xdr; | 1707 | struct xdr_stream xdr; |
| 1812 | struct compound_hdr hdr = { | 1708 | struct compound_hdr hdr = { |
| 1813 | .nops = 2, | 1709 | .nops = 0, |
| 1814 | }; | 1710 | }; |
| 1815 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | 1711 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; |
| 1816 | int replen; | 1712 | int replen; |
| 1817 | int status; | ||
| 1818 | 1713 | ||
| 1819 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1714 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1820 | encode_compound_hdr(&xdr, &hdr); | 1715 | encode_compound_hdr(&xdr, &hdr); |
| 1821 | status = encode_putfh(&xdr, args->fh); | 1716 | encode_putfh(&xdr, args->fh, &hdr); |
| 1822 | if(status) | 1717 | encode_readdir(&xdr, args, req, &hdr); |
| 1823 | goto out; | ||
| 1824 | status = encode_readdir(&xdr, args, req); | ||
| 1825 | 1718 | ||
| 1826 | /* set up reply kvec | 1719 | /* set up reply kvec |
| 1827 | * toplevel_status + taglen + rescount + OP_PUTFH + status | 1720 | * toplevel_status + taglen + rescount + OP_PUTFH + status |
| @@ -1833,9 +1726,8 @@ static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nf | |||
| 1833 | dprintk("%s: inlined page args = (%u, %p, %u, %u)\n", | 1726 | dprintk("%s: inlined page args = (%u, %p, %u, %u)\n", |
| 1834 | __func__, replen, args->pages, | 1727 | __func__, replen, args->pages, |
| 1835 | args->pgbase, args->count); | 1728 | args->pgbase, args->count); |
| 1836 | 1729 | encode_nops(&hdr); | |
| 1837 | out: | 1730 | return 0; |
| 1838 | return status; | ||
| 1839 | } | 1731 | } |
| 1840 | 1732 | ||
| 1841 | /* | 1733 | /* |
| @@ -1846,18 +1738,14 @@ static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readarg | |||
| 1846 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | 1738 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; |
| 1847 | struct xdr_stream xdr; | 1739 | struct xdr_stream xdr; |
| 1848 | struct compound_hdr hdr = { | 1740 | struct compound_hdr hdr = { |
| 1849 | .nops = 2, | 1741 | .nops = 0, |
| 1850 | }; | 1742 | }; |
| 1851 | int replen, status; | 1743 | int replen; |
| 1852 | 1744 | ||
| 1853 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1745 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1854 | encode_compound_hdr(&xdr, &hdr); | 1746 | encode_compound_hdr(&xdr, &hdr); |
| 1855 | status = encode_putfh(&xdr, args->fh); | 1747 | encode_putfh(&xdr, args->fh, &hdr); |
| 1856 | if (status) | 1748 | encode_read(&xdr, args, &hdr); |
| 1857 | goto out; | ||
| 1858 | status = encode_read(&xdr, args); | ||
| 1859 | if (status) | ||
| 1860 | goto out; | ||
| 1861 | 1749 | ||
| 1862 | /* set up reply kvec | 1750 | /* set up reply kvec |
| 1863 | * toplevel status + taglen=0 + rescount + OP_PUTFH + status | 1751 | * toplevel status + taglen=0 + rescount + OP_PUTFH + status |
| @@ -1867,33 +1755,27 @@ static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readarg | |||
| 1867 | xdr_inline_pages(&req->rq_rcv_buf, replen, | 1755 | xdr_inline_pages(&req->rq_rcv_buf, replen, |
| 1868 | args->pages, args->pgbase, args->count); | 1756 | args->pages, args->pgbase, args->count); |
| 1869 | req->rq_rcv_buf.flags |= XDRBUF_READ; | 1757 | req->rq_rcv_buf.flags |= XDRBUF_READ; |
| 1870 | out: | 1758 | encode_nops(&hdr); |
| 1871 | return status; | 1759 | return 0; |
| 1872 | } | 1760 | } |
| 1873 | 1761 | ||
| 1874 | /* | 1762 | /* |
| 1875 | * Encode an SETATTR request | 1763 | * Encode an SETATTR request |
| 1876 | */ | 1764 | */ |
| 1877 | static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, __be32 *p, struct nfs_setattrargs *args) | 1765 | static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, __be32 *p, struct nfs_setattrargs *args) |
| 1878 | |||
| 1879 | { | 1766 | { |
| 1880 | struct xdr_stream xdr; | 1767 | struct xdr_stream xdr; |
| 1881 | struct compound_hdr hdr = { | 1768 | struct compound_hdr hdr = { |
| 1882 | .nops = 3, | 1769 | .nops = 0, |
| 1883 | }; | 1770 | }; |
| 1884 | int status; | 1771 | |
| 1885 | 1772 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | |
| 1886 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1773 | encode_compound_hdr(&xdr, &hdr); |
| 1887 | encode_compound_hdr(&xdr, &hdr); | 1774 | encode_putfh(&xdr, args->fh, &hdr); |
| 1888 | status = encode_putfh(&xdr, args->fh); | 1775 | encode_setattr(&xdr, args, args->server, &hdr); |
| 1889 | if(status) | 1776 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| 1890 | goto out; | 1777 | encode_nops(&hdr); |
| 1891 | status = encode_setattr(&xdr, args, args->server); | 1778 | return 0; |
| 1892 | if(status) | ||
| 1893 | goto out; | ||
| 1894 | status = encode_getfattr(&xdr, args->bitmask); | ||
| 1895 | out: | ||
| 1896 | return status; | ||
| 1897 | } | 1779 | } |
| 1898 | 1780 | ||
| 1899 | /* | 1781 | /* |
| @@ -1906,22 +1788,21 @@ nfs4_xdr_enc_getacl(struct rpc_rqst *req, __be32 *p, | |||
| 1906 | struct xdr_stream xdr; | 1788 | struct xdr_stream xdr; |
| 1907 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | 1789 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; |
| 1908 | struct compound_hdr hdr = { | 1790 | struct compound_hdr hdr = { |
| 1909 | .nops = 2, | 1791 | .nops = 0, |
| 1910 | }; | 1792 | }; |
| 1911 | int replen, status; | 1793 | int replen; |
| 1912 | 1794 | ||
| 1913 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1795 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1914 | encode_compound_hdr(&xdr, &hdr); | 1796 | encode_compound_hdr(&xdr, &hdr); |
| 1915 | status = encode_putfh(&xdr, args->fh); | 1797 | encode_putfh(&xdr, args->fh, &hdr); |
| 1916 | if (status) | 1798 | encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0, &hdr); |
| 1917 | goto out; | 1799 | |
| 1918 | status = encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0); | ||
| 1919 | /* set up reply buffer: */ | 1800 | /* set up reply buffer: */ |
| 1920 | replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_getacl_sz) << 2; | 1801 | replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_getacl_sz) << 2; |
| 1921 | xdr_inline_pages(&req->rq_rcv_buf, replen, | 1802 | xdr_inline_pages(&req->rq_rcv_buf, replen, |
| 1922 | args->acl_pages, args->acl_pgbase, args->acl_len); | 1803 | args->acl_pages, args->acl_pgbase, args->acl_len); |
| 1923 | out: | 1804 | encode_nops(&hdr); |
| 1924 | return status; | 1805 | return 0; |
| 1925 | } | 1806 | } |
| 1926 | 1807 | ||
| 1927 | /* | 1808 | /* |
| @@ -1931,22 +1812,17 @@ static int nfs4_xdr_enc_write(struct rpc_rqst *req, __be32 *p, struct nfs_writea | |||
| 1931 | { | 1812 | { |
| 1932 | struct xdr_stream xdr; | 1813 | struct xdr_stream xdr; |
| 1933 | struct compound_hdr hdr = { | 1814 | struct compound_hdr hdr = { |
| 1934 | .nops = 3, | 1815 | .nops = 0, |
| 1935 | }; | 1816 | }; |
| 1936 | int status; | ||
| 1937 | 1817 | ||
| 1938 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1818 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1939 | encode_compound_hdr(&xdr, &hdr); | 1819 | encode_compound_hdr(&xdr, &hdr); |
| 1940 | status = encode_putfh(&xdr, args->fh); | 1820 | encode_putfh(&xdr, args->fh, &hdr); |
| 1941 | if (status) | 1821 | encode_write(&xdr, args, &hdr); |
| 1942 | goto out; | ||
| 1943 | status = encode_write(&xdr, args); | ||
| 1944 | if (status) | ||
| 1945 | goto out; | ||
| 1946 | req->rq_snd_buf.flags |= XDRBUF_WRITE; | 1822 | req->rq_snd_buf.flags |= XDRBUF_WRITE; |
| 1947 | status = encode_getfattr(&xdr, args->bitmask); | 1823 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| 1948 | out: | 1824 | encode_nops(&hdr); |
| 1949 | return status; | 1825 | return 0; |
| 1950 | } | 1826 | } |
| 1951 | 1827 | ||
| 1952 | /* | 1828 | /* |
| @@ -1956,21 +1832,16 @@ static int nfs4_xdr_enc_commit(struct rpc_rqst *req, __be32 *p, struct nfs_write | |||
| 1956 | { | 1832 | { |
| 1957 | struct xdr_stream xdr; | 1833 | struct xdr_stream xdr; |
| 1958 | struct compound_hdr hdr = { | 1834 | struct compound_hdr hdr = { |
| 1959 | .nops = 3, | 1835 | .nops = 0, |
| 1960 | }; | 1836 | }; |
| 1961 | int status; | ||
| 1962 | 1837 | ||
| 1963 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1838 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1964 | encode_compound_hdr(&xdr, &hdr); | 1839 | encode_compound_hdr(&xdr, &hdr); |
| 1965 | status = encode_putfh(&xdr, args->fh); | 1840 | encode_putfh(&xdr, args->fh, &hdr); |
| 1966 | if (status) | 1841 | encode_commit(&xdr, args, &hdr); |
| 1967 | goto out; | 1842 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| 1968 | status = encode_commit(&xdr, args); | 1843 | encode_nops(&hdr); |
| 1969 | if (status) | 1844 | return 0; |
| 1970 | goto out; | ||
| 1971 | status = encode_getfattr(&xdr, args->bitmask); | ||
| 1972 | out: | ||
| 1973 | return status; | ||
| 1974 | } | 1845 | } |
| 1975 | 1846 | ||
| 1976 | /* | 1847 | /* |
| @@ -1980,16 +1851,15 @@ static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs4_fsin | |||
| 1980 | { | 1851 | { |
| 1981 | struct xdr_stream xdr; | 1852 | struct xdr_stream xdr; |
| 1982 | struct compound_hdr hdr = { | 1853 | struct compound_hdr hdr = { |
| 1983 | .nops = 2, | 1854 | .nops = 0, |
| 1984 | }; | 1855 | }; |
| 1985 | int status; | ||
| 1986 | 1856 | ||
| 1987 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1857 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1988 | encode_compound_hdr(&xdr, &hdr); | 1858 | encode_compound_hdr(&xdr, &hdr); |
| 1989 | status = encode_putfh(&xdr, args->fh); | 1859 | encode_putfh(&xdr, args->fh, &hdr); |
| 1990 | if (!status) | 1860 | encode_fsinfo(&xdr, args->bitmask, &hdr); |
| 1991 | status = encode_fsinfo(&xdr, args->bitmask); | 1861 | encode_nops(&hdr); |
| 1992 | return status; | 1862 | return 0; |
| 1993 | } | 1863 | } |
| 1994 | 1864 | ||
| 1995 | /* | 1865 | /* |
| @@ -1999,17 +1869,16 @@ static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, __be32 *p, const struct n | |||
| 1999 | { | 1869 | { |
| 2000 | struct xdr_stream xdr; | 1870 | struct xdr_stream xdr; |
| 2001 | struct compound_hdr hdr = { | 1871 | struct compound_hdr hdr = { |
| 2002 | .nops = 2, | 1872 | .nops = 0, |
| 2003 | }; | 1873 | }; |
| 2004 | int status; | ||
| 2005 | 1874 | ||
| 2006 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1875 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 2007 | encode_compound_hdr(&xdr, &hdr); | 1876 | encode_compound_hdr(&xdr, &hdr); |
| 2008 | status = encode_putfh(&xdr, args->fh); | 1877 | encode_putfh(&xdr, args->fh, &hdr); |
| 2009 | if (!status) | 1878 | encode_getattr_one(&xdr, args->bitmask[0] & nfs4_pathconf_bitmap[0], |
| 2010 | status = encode_getattr_one(&xdr, | 1879 | &hdr); |
| 2011 | args->bitmask[0] & nfs4_pathconf_bitmap[0]); | 1880 | encode_nops(&hdr); |
| 2012 | return status; | 1881 | return 0; |
| 2013 | } | 1882 | } |
| 2014 | 1883 | ||
| 2015 | /* | 1884 | /* |
| @@ -2019,18 +1888,16 @@ static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
| 2019 | { | 1888 | { |
| 2020 | struct xdr_stream xdr; | 1889 | struct xdr_stream xdr; |
| 2021 | struct compound_hdr hdr = { | 1890 | struct compound_hdr hdr = { |
| 2022 | .nops = 2, | 1891 | .nops = 0, |
| 2023 | }; | 1892 | }; |
| 2024 | int status; | ||
| 2025 | 1893 | ||
| 2026 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1894 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 2027 | encode_compound_hdr(&xdr, &hdr); | 1895 | encode_compound_hdr(&xdr, &hdr); |
| 2028 | status = encode_putfh(&xdr, args->fh); | 1896 | encode_putfh(&xdr, args->fh, &hdr); |
| 2029 | if (status == 0) | 1897 | encode_getattr_two(&xdr, args->bitmask[0] & nfs4_statfs_bitmap[0], |
| 2030 | status = encode_getattr_two(&xdr, | 1898 | args->bitmask[1] & nfs4_statfs_bitmap[1], &hdr); |
| 2031 | args->bitmask[0] & nfs4_statfs_bitmap[0], | 1899 | encode_nops(&hdr); |
| 2032 | args->bitmask[1] & nfs4_statfs_bitmap[1]); | 1900 | return 0; |
| 2033 | return status; | ||
| 2034 | } | 1901 | } |
| 2035 | 1902 | ||
| 2036 | /* | 1903 | /* |
| @@ -2040,19 +1907,18 @@ static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, __be32 *p, const struc | |||
| 2040 | { | 1907 | { |
| 2041 | struct xdr_stream xdr; | 1908 | struct xdr_stream xdr; |
| 2042 | struct compound_hdr hdr = { | 1909 | struct compound_hdr hdr = { |
| 2043 | .nops = 2, | 1910 | .nops = 0, |
| 2044 | }; | 1911 | }; |
| 2045 | int status; | ||
| 2046 | 1912 | ||
| 2047 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1913 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 2048 | encode_compound_hdr(&xdr, &hdr); | 1914 | encode_compound_hdr(&xdr, &hdr); |
| 2049 | status = encode_putfh(&xdr, fhandle); | 1915 | encode_putfh(&xdr, fhandle, &hdr); |
| 2050 | if (status == 0) | 1916 | encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS| |
| 2051 | status = encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS| | 1917 | FATTR4_WORD0_LINK_SUPPORT| |
| 2052 | FATTR4_WORD0_LINK_SUPPORT| | 1918 | FATTR4_WORD0_SYMLINK_SUPPORT| |
| 2053 | FATTR4_WORD0_SYMLINK_SUPPORT| | 1919 | FATTR4_WORD0_ACLSUPPORT, &hdr); |
| 2054 | FATTR4_WORD0_ACLSUPPORT); | 1920 | encode_nops(&hdr); |
| 2055 | return status; | 1921 | return 0; |
| 2056 | } | 1922 | } |
| 2057 | 1923 | ||
| 2058 | /* | 1924 | /* |
| @@ -2062,12 +1928,14 @@ static int nfs4_xdr_enc_renew(struct rpc_rqst *req, __be32 *p, struct nfs_client | |||
| 2062 | { | 1928 | { |
| 2063 | struct xdr_stream xdr; | 1929 | struct xdr_stream xdr; |
| 2064 | struct compound_hdr hdr = { | 1930 | struct compound_hdr hdr = { |
| 2065 | .nops = 1, | 1931 | .nops = 0, |
| 2066 | }; | 1932 | }; |
| 2067 | 1933 | ||
| 2068 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1934 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 2069 | encode_compound_hdr(&xdr, &hdr); | 1935 | encode_compound_hdr(&xdr, &hdr); |
| 2070 | return encode_renew(&xdr, clp); | 1936 | encode_renew(&xdr, clp, &hdr); |
| 1937 | encode_nops(&hdr); | ||
| 1938 | return 0; | ||
| 2071 | } | 1939 | } |
| 2072 | 1940 | ||
| 2073 | /* | 1941 | /* |
| @@ -2077,12 +1945,14 @@ static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, __be32 *p, struct nfs4 | |||
| 2077 | { | 1945 | { |
| 2078 | struct xdr_stream xdr; | 1946 | struct xdr_stream xdr; |
| 2079 | struct compound_hdr hdr = { | 1947 | struct compound_hdr hdr = { |
| 2080 | .nops = 1, | 1948 | .nops = 0, |
| 2081 | }; | 1949 | }; |
| 2082 | 1950 | ||
| 2083 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1951 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 2084 | encode_compound_hdr(&xdr, &hdr); | 1952 | encode_compound_hdr(&xdr, &hdr); |
| 2085 | return encode_setclientid(&xdr, sc); | 1953 | encode_setclientid(&xdr, sc, &hdr); |
| 1954 | encode_nops(&hdr); | ||
| 1955 | return 0; | ||
| 2086 | } | 1956 | } |
| 2087 | 1957 | ||
| 2088 | /* | 1958 | /* |
| @@ -2092,19 +1962,17 @@ static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, str | |||
| 2092 | { | 1962 | { |
| 2093 | struct xdr_stream xdr; | 1963 | struct xdr_stream xdr; |
| 2094 | struct compound_hdr hdr = { | 1964 | struct compound_hdr hdr = { |
| 2095 | .nops = 3, | 1965 | .nops = 0, |
| 2096 | }; | 1966 | }; |
| 2097 | const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 }; | 1967 | const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 }; |
| 2098 | int status; | ||
| 2099 | 1968 | ||
| 2100 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1969 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 2101 | encode_compound_hdr(&xdr, &hdr); | 1970 | encode_compound_hdr(&xdr, &hdr); |
| 2102 | status = encode_setclientid_confirm(&xdr, clp); | 1971 | encode_setclientid_confirm(&xdr, clp, &hdr); |
| 2103 | if (!status) | 1972 | encode_putrootfh(&xdr, &hdr); |
| 2104 | status = encode_putrootfh(&xdr); | 1973 | encode_fsinfo(&xdr, lease_bitmap, &hdr); |
| 2105 | if (!status) | 1974 | encode_nops(&hdr); |
| 2106 | status = encode_fsinfo(&xdr, lease_bitmap); | 1975 | return 0; |
| 2107 | return status; | ||
| 2108 | } | 1976 | } |
| 2109 | 1977 | ||
| 2110 | /* | 1978 | /* |
| @@ -2114,21 +1982,16 @@ static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, __be32 *p, const struc | |||
| 2114 | { | 1982 | { |
| 2115 | struct xdr_stream xdr; | 1983 | struct xdr_stream xdr; |
| 2116 | struct compound_hdr hdr = { | 1984 | struct compound_hdr hdr = { |
| 2117 | .nops = 3, | 1985 | .nops = 0, |
| 2118 | }; | 1986 | }; |
| 2119 | int status; | ||
| 2120 | 1987 | ||
| 2121 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1988 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 2122 | encode_compound_hdr(&xdr, &hdr); | 1989 | encode_compound_hdr(&xdr, &hdr); |
| 2123 | status = encode_putfh(&xdr, args->fhandle); | 1990 | encode_putfh(&xdr, args->fhandle, &hdr); |
| 2124 | if (status != 0) | 1991 | encode_delegreturn(&xdr, args->stateid, &hdr); |
| 2125 | goto out; | 1992 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| 2126 | status = encode_delegreturn(&xdr, args->stateid); | 1993 | encode_nops(&hdr); |
| 2127 | if (status != 0) | 1994 | return 0; |
| 2128 | goto out; | ||
| 2129 | status = encode_getfattr(&xdr, args->bitmask); | ||
| 2130 | out: | ||
| 2131 | return status; | ||
| 2132 | } | 1995 | } |
| 2133 | 1996 | ||
| 2134 | /* | 1997 | /* |
| @@ -2138,20 +2001,17 @@ static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs | |||
| 2138 | { | 2001 | { |
| 2139 | struct xdr_stream xdr; | 2002 | struct xdr_stream xdr; |
| 2140 | struct compound_hdr hdr = { | 2003 | struct compound_hdr hdr = { |
| 2141 | .nops = 3, | 2004 | .nops = 0, |
| 2142 | }; | 2005 | }; |
| 2143 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | 2006 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; |
| 2144 | int replen; | 2007 | int replen; |
| 2145 | int status; | ||
| 2146 | 2008 | ||
| 2147 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2009 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 2148 | encode_compound_hdr(&xdr, &hdr); | 2010 | encode_compound_hdr(&xdr, &hdr); |
| 2149 | if ((status = encode_putfh(&xdr, args->dir_fh)) != 0) | 2011 | encode_putfh(&xdr, args->dir_fh, &hdr); |
| 2150 | goto out; | 2012 | encode_lookup(&xdr, args->name, &hdr); |
| 2151 | if ((status = encode_lookup(&xdr, args->name)) != 0) | 2013 | encode_fs_locations(&xdr, args->bitmask, &hdr); |
| 2152 | goto out; | 2014 | |
| 2153 | if ((status = encode_fs_locations(&xdr, args->bitmask)) != 0) | ||
| 2154 | goto out; | ||
| 2155 | /* set up reply | 2015 | /* set up reply |
| 2156 | * toplevel_status + OP_PUTFH + status | 2016 | * toplevel_status + OP_PUTFH + status |
| 2157 | * + OP_LOOKUP + status + OP_GETATTR + status = 7 | 2017 | * + OP_LOOKUP + status + OP_GETATTR + status = 7 |
| @@ -2159,8 +2019,8 @@ static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs | |||
| 2159 | replen = (RPC_REPHDRSIZE + auth->au_rslack + 7) << 2; | 2019 | replen = (RPC_REPHDRSIZE + auth->au_rslack + 7) << 2; |
| 2160 | xdr_inline_pages(&req->rq_rcv_buf, replen, &args->page, | 2020 | xdr_inline_pages(&req->rq_rcv_buf, replen, &args->page, |
| 2161 | 0, PAGE_SIZE); | 2021 | 0, PAGE_SIZE); |
| 2162 | out: | 2022 | encode_nops(&hdr); |
| 2163 | return status; | 2023 | return 0; |
| 2164 | } | 2024 | } |
| 2165 | 2025 | ||
| 2166 | /* | 2026 | /* |
| @@ -2217,11 +2077,13 @@ static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
| 2217 | READ_BUF(8); | 2077 | READ_BUF(8); |
| 2218 | READ32(hdr->status); | 2078 | READ32(hdr->status); |
| 2219 | READ32(hdr->taglen); | 2079 | READ32(hdr->taglen); |
| 2220 | 2080 | ||
| 2221 | READ_BUF(hdr->taglen + 4); | 2081 | READ_BUF(hdr->taglen + 4); |
| 2222 | hdr->tag = (char *)p; | 2082 | hdr->tag = (char *)p; |
| 2223 | p += XDR_QUADLEN(hdr->taglen); | 2083 | p += XDR_QUADLEN(hdr->taglen); |
| 2224 | READ32(hdr->nops); | 2084 | READ32(hdr->nops); |
| 2085 | if (unlikely(hdr->nops < 1)) | ||
| 2086 | return nfs4_stat_to_errno(hdr->status); | ||
| 2225 | return 0; | 2087 | return 0; |
| 2226 | } | 2088 | } |
| 2227 | 2089 | ||
| @@ -3047,8 +2909,7 @@ static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) | |||
| 3047 | static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res) | 2909 | static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res) |
| 3048 | { | 2910 | { |
| 3049 | __be32 *savep; | 2911 | __be32 *savep; |
| 3050 | uint32_t attrlen, | 2912 | uint32_t attrlen, bitmap[2] = {0}; |
| 3051 | bitmap[2] = {0}; | ||
| 3052 | int status; | 2913 | int status; |
| 3053 | 2914 | ||
| 3054 | if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) | 2915 | if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) |
| @@ -3070,14 +2931,13 @@ xdr_error: | |||
| 3070 | dprintk("%s: xdr returned %d!\n", __func__, -status); | 2931 | dprintk("%s: xdr returned %d!\n", __func__, -status); |
| 3071 | return status; | 2932 | return status; |
| 3072 | } | 2933 | } |
| 3073 | 2934 | ||
| 3074 | static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat) | 2935 | static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat) |
| 3075 | { | 2936 | { |
| 3076 | __be32 *savep; | 2937 | __be32 *savep; |
| 3077 | uint32_t attrlen, | 2938 | uint32_t attrlen, bitmap[2] = {0}; |
| 3078 | bitmap[2] = {0}; | ||
| 3079 | int status; | 2939 | int status; |
| 3080 | 2940 | ||
| 3081 | if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) | 2941 | if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) |
| 3082 | goto xdr_error; | 2942 | goto xdr_error; |
| 3083 | if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) | 2943 | if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) |
| @@ -3107,10 +2967,9 @@ xdr_error: | |||
| 3107 | static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf) | 2967 | static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf) |
| 3108 | { | 2968 | { |
| 3109 | __be32 *savep; | 2969 | __be32 *savep; |
| 3110 | uint32_t attrlen, | 2970 | uint32_t attrlen, bitmap[2] = {0}; |
| 3111 | bitmap[2] = {0}; | ||
| 3112 | int status; | 2971 | int status; |
| 3113 | 2972 | ||
| 3114 | if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) | 2973 | if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) |
| 3115 | goto xdr_error; | 2974 | goto xdr_error; |
| 3116 | if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) | 2975 | if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) |
| @@ -3256,7 +3115,7 @@ static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh) | |||
| 3256 | static int decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) | 3115 | static int decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) |
| 3257 | { | 3116 | { |
| 3258 | int status; | 3117 | int status; |
| 3259 | 3118 | ||
| 3260 | status = decode_op_hdr(xdr, OP_LINK); | 3119 | status = decode_op_hdr(xdr, OP_LINK); |
| 3261 | if (status) | 3120 | if (status) |
| 3262 | return status; | 3121 | return status; |
| @@ -3344,27 +3203,27 @@ static int decode_lookup(struct xdr_stream *xdr) | |||
| 3344 | /* This is too sick! */ | 3203 | /* This is too sick! */ |
| 3345 | static int decode_space_limit(struct xdr_stream *xdr, u64 *maxsize) | 3204 | static int decode_space_limit(struct xdr_stream *xdr, u64 *maxsize) |
| 3346 | { | 3205 | { |
| 3347 | __be32 *p; | 3206 | __be32 *p; |
| 3348 | uint32_t limit_type, nblocks, blocksize; | 3207 | uint32_t limit_type, nblocks, blocksize; |
| 3349 | 3208 | ||
| 3350 | READ_BUF(12); | 3209 | READ_BUF(12); |
| 3351 | READ32(limit_type); | 3210 | READ32(limit_type); |
| 3352 | switch (limit_type) { | 3211 | switch (limit_type) { |
| 3353 | case 1: | 3212 | case 1: |
| 3354 | READ64(*maxsize); | 3213 | READ64(*maxsize); |
| 3355 | break; | 3214 | break; |
| 3356 | case 2: | 3215 | case 2: |
| 3357 | READ32(nblocks); | 3216 | READ32(nblocks); |
| 3358 | READ32(blocksize); | 3217 | READ32(blocksize); |
| 3359 | *maxsize = (uint64_t)nblocks * (uint64_t)blocksize; | 3218 | *maxsize = (uint64_t)nblocks * (uint64_t)blocksize; |
| 3360 | } | 3219 | } |
| 3361 | return 0; | 3220 | return 0; |
| 3362 | } | 3221 | } |
| 3363 | 3222 | ||
| 3364 | static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res) | 3223 | static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res) |
| 3365 | { | 3224 | { |
| 3366 | __be32 *p; | 3225 | __be32 *p; |
| 3367 | uint32_t delegation_type; | 3226 | uint32_t delegation_type; |
| 3368 | 3227 | ||
| 3369 | READ_BUF(4); | 3228 | READ_BUF(4); |
| 3370 | READ32(delegation_type); | 3229 | READ32(delegation_type); |
| @@ -3375,13 +3234,14 @@ static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res) | |||
| 3375 | READ_BUF(NFS4_STATEID_SIZE+4); | 3234 | READ_BUF(NFS4_STATEID_SIZE+4); |
| 3376 | COPYMEM(res->delegation.data, NFS4_STATEID_SIZE); | 3235 | COPYMEM(res->delegation.data, NFS4_STATEID_SIZE); |
| 3377 | READ32(res->do_recall); | 3236 | READ32(res->do_recall); |
| 3237 | |||
| 3378 | switch (delegation_type) { | 3238 | switch (delegation_type) { |
| 3379 | case NFS4_OPEN_DELEGATE_READ: | 3239 | case NFS4_OPEN_DELEGATE_READ: |
| 3380 | res->delegation_type = FMODE_READ; | 3240 | res->delegation_type = FMODE_READ; |
| 3381 | break; | 3241 | break; |
| 3382 | case NFS4_OPEN_DELEGATE_WRITE: | 3242 | case NFS4_OPEN_DELEGATE_WRITE: |
| 3383 | res->delegation_type = FMODE_WRITE|FMODE_READ; | 3243 | res->delegation_type = FMODE_WRITE|FMODE_READ; |
| 3384 | if (decode_space_limit(xdr, &res->maxsize) < 0) | 3244 | if (decode_space_limit(xdr, &res->maxsize) < 0) |
| 3385 | return -EIO; | 3245 | return -EIO; |
| 3386 | } | 3246 | } |
| 3387 | return decode_ace(xdr, NULL, res->server->nfs_client); | 3247 | return decode_ace(xdr, NULL, res->server->nfs_client); |
| @@ -3389,27 +3249,27 @@ static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res) | |||
| 3389 | 3249 | ||
| 3390 | static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) | 3250 | static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) |
| 3391 | { | 3251 | { |
| 3392 | __be32 *p; | 3252 | __be32 *p; |
| 3393 | uint32_t savewords, bmlen, i; | 3253 | uint32_t savewords, bmlen, i; |
| 3394 | int status; | 3254 | int status; |
| 3395 | 3255 | ||
| 3396 | status = decode_op_hdr(xdr, OP_OPEN); | 3256 | status = decode_op_hdr(xdr, OP_OPEN); |
| 3397 | if (status != -EIO) | 3257 | if (status != -EIO) |
| 3398 | nfs_increment_open_seqid(status, res->seqid); | 3258 | nfs_increment_open_seqid(status, res->seqid); |
| 3399 | if (status) | 3259 | if (status) |
| 3400 | return status; | 3260 | return status; |
| 3401 | READ_BUF(NFS4_STATEID_SIZE); | 3261 | READ_BUF(NFS4_STATEID_SIZE); |
| 3402 | COPYMEM(res->stateid.data, NFS4_STATEID_SIZE); | 3262 | COPYMEM(res->stateid.data, NFS4_STATEID_SIZE); |
| 3403 | 3263 | ||
| 3404 | decode_change_info(xdr, &res->cinfo); | 3264 | decode_change_info(xdr, &res->cinfo); |
| 3405 | 3265 | ||
| 3406 | READ_BUF(8); | 3266 | READ_BUF(8); |
| 3407 | READ32(res->rflags); | 3267 | READ32(res->rflags); |
| 3408 | READ32(bmlen); | 3268 | READ32(bmlen); |
| 3409 | if (bmlen > 10) | 3269 | if (bmlen > 10) |
| 3410 | goto xdr_error; | 3270 | goto xdr_error; |
| 3411 | 3271 | ||
| 3412 | READ_BUF(bmlen << 2); | 3272 | READ_BUF(bmlen << 2); |
| 3413 | savewords = min_t(uint32_t, bmlen, NFS4_BITMAP_SIZE); | 3273 | savewords = min_t(uint32_t, bmlen, NFS4_BITMAP_SIZE); |
| 3414 | for (i = 0; i < savewords; ++i) | 3274 | for (i = 0; i < savewords; ++i) |
| 3415 | READ32(res->attrset[i]); | 3275 | READ32(res->attrset[i]); |
| @@ -3424,17 +3284,17 @@ xdr_error: | |||
| 3424 | 3284 | ||
| 3425 | static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res) | 3285 | static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res) |
| 3426 | { | 3286 | { |
| 3427 | __be32 *p; | 3287 | __be32 *p; |
| 3428 | int status; | 3288 | int status; |
| 3429 | 3289 | ||
| 3430 | status = decode_op_hdr(xdr, OP_OPEN_CONFIRM); | 3290 | status = decode_op_hdr(xdr, OP_OPEN_CONFIRM); |
| 3431 | if (status != -EIO) | 3291 | if (status != -EIO) |
| 3432 | nfs_increment_open_seqid(status, res->seqid); | 3292 | nfs_increment_open_seqid(status, res->seqid); |
| 3433 | if (status) | 3293 | if (status) |
| 3434 | return status; | 3294 | return status; |
| 3435 | READ_BUF(NFS4_STATEID_SIZE); | 3295 | READ_BUF(NFS4_STATEID_SIZE); |
| 3436 | COPYMEM(res->stateid.data, NFS4_STATEID_SIZE); | 3296 | COPYMEM(res->stateid.data, NFS4_STATEID_SIZE); |
| 3437 | return 0; | 3297 | return 0; |
| 3438 | } | 3298 | } |
| 3439 | 3299 | ||
| 3440 | static int decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *res) | 3300 | static int decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *res) |
| @@ -3562,7 +3422,7 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
| 3562 | dprintk("NFS: readdir reply truncated!\n"); | 3422 | dprintk("NFS: readdir reply truncated!\n"); |
| 3563 | entry[1] = 1; | 3423 | entry[1] = 1; |
| 3564 | } | 3424 | } |
| 3565 | out: | 3425 | out: |
| 3566 | kunmap_atomic(kaddr, KM_USER0); | 3426 | kunmap_atomic(kaddr, KM_USER0); |
| 3567 | return 0; | 3427 | return 0; |
| 3568 | short_pkt: | 3428 | short_pkt: |
| @@ -3718,7 +3578,6 @@ static int decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res) | |||
| 3718 | uint32_t bmlen; | 3578 | uint32_t bmlen; |
| 3719 | int status; | 3579 | int status; |
| 3720 | 3580 | ||
| 3721 | |||
| 3722 | status = decode_op_hdr(xdr, OP_SETATTR); | 3581 | status = decode_op_hdr(xdr, OP_SETATTR); |
| 3723 | if (status) | 3582 | if (status) |
| 3724 | return status; | 3583 | return status; |
| @@ -3738,7 +3597,7 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp) | |||
| 3738 | READ32(opnum); | 3597 | READ32(opnum); |
| 3739 | if (opnum != OP_SETCLIENTID) { | 3598 | if (opnum != OP_SETCLIENTID) { |
| 3740 | dprintk("nfs: decode_setclientid: Server returned operation" | 3599 | dprintk("nfs: decode_setclientid: Server returned operation" |
| 3741 | " %d\n", opnum); | 3600 | " %d\n", opnum); |
| 3742 | return -EIO; | 3601 | return -EIO; |
| 3743 | } | 3602 | } |
| 3744 | READ32(nfserr); | 3603 | READ32(nfserr); |
| @@ -3792,34 +3651,34 @@ static int decode_delegreturn(struct xdr_stream *xdr) | |||
| 3792 | } | 3651 | } |
| 3793 | 3652 | ||
| 3794 | /* | 3653 | /* |
| 3654 | * END OF "GENERIC" DECODE ROUTINES. | ||
| 3655 | */ | ||
| 3656 | |||
| 3657 | /* | ||
| 3795 | * Decode OPEN_DOWNGRADE response | 3658 | * Decode OPEN_DOWNGRADE response |
| 3796 | */ | 3659 | */ |
| 3797 | static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res) | 3660 | static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res) |
| 3798 | { | 3661 | { |
| 3799 | struct xdr_stream xdr; | 3662 | struct xdr_stream xdr; |
| 3800 | struct compound_hdr hdr; | 3663 | struct compound_hdr hdr; |
| 3801 | int status; | 3664 | int status; |
| 3802 | 3665 | ||
| 3803 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 3666 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
| 3804 | status = decode_compound_hdr(&xdr, &hdr); | 3667 | status = decode_compound_hdr(&xdr, &hdr); |
| 3805 | if (status) | 3668 | if (status) |
| 3806 | goto out; | 3669 | goto out; |
| 3807 | status = decode_putfh(&xdr); | 3670 | status = decode_putfh(&xdr); |
| 3808 | if (status) | 3671 | if (status) |
| 3809 | goto out; | 3672 | goto out; |
| 3810 | status = decode_open_downgrade(&xdr, res); | 3673 | status = decode_open_downgrade(&xdr, res); |
| 3811 | if (status != 0) | 3674 | if (status != 0) |
| 3812 | goto out; | 3675 | goto out; |
| 3813 | decode_getfattr(&xdr, res->fattr, res->server); | 3676 | decode_getfattr(&xdr, res->fattr, res->server); |
| 3814 | out: | 3677 | out: |
| 3815 | return status; | 3678 | return status; |
| 3816 | } | 3679 | } |
| 3817 | 3680 | ||
| 3818 | /* | 3681 | /* |
| 3819 | * END OF "GENERIC" DECODE ROUTINES. | ||
| 3820 | */ | ||
| 3821 | |||
| 3822 | /* | ||
| 3823 | * Decode ACCESS response | 3682 | * Decode ACCESS response |
| 3824 | */ | 3683 | */ |
| 3825 | static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_accessres *res) | 3684 | static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_accessres *res) |
| @@ -3827,7 +3686,7 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_ac | |||
| 3827 | struct xdr_stream xdr; | 3686 | struct xdr_stream xdr; |
| 3828 | struct compound_hdr hdr; | 3687 | struct compound_hdr hdr; |
| 3829 | int status; | 3688 | int status; |
| 3830 | 3689 | ||
| 3831 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 3690 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
| 3832 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 3691 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) |
| 3833 | goto out; | 3692 | goto out; |
| @@ -3850,7 +3709,7 @@ static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lo | |||
| 3850 | struct xdr_stream xdr; | 3709 | struct xdr_stream xdr; |
| 3851 | struct compound_hdr hdr; | 3710 | struct compound_hdr hdr; |
| 3852 | int status; | 3711 | int status; |
| 3853 | 3712 | ||
| 3854 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 3713 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
| 3855 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 3714 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) |
| 3856 | goto out; | 3715 | goto out; |
| @@ -3873,7 +3732,7 @@ static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, __be32 *p, struct nf | |||
| 3873 | struct xdr_stream xdr; | 3732 | struct xdr_stream xdr; |
| 3874 | struct compound_hdr hdr; | 3733 | struct compound_hdr hdr; |
| 3875 | int status; | 3734 | int status; |
| 3876 | 3735 | ||
| 3877 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 3736 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
| 3878 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 3737 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) |
| 3879 | goto out; | 3738 | goto out; |
| @@ -3893,7 +3752,7 @@ static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs_rem | |||
| 3893 | struct xdr_stream xdr; | 3752 | struct xdr_stream xdr; |
| 3894 | struct compound_hdr hdr; | 3753 | struct compound_hdr hdr; |
| 3895 | int status; | 3754 | int status; |
| 3896 | 3755 | ||
| 3897 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 3756 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
| 3898 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 3757 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) |
| 3899 | goto out; | 3758 | goto out; |
| @@ -3914,7 +3773,7 @@ static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_re | |||
| 3914 | struct xdr_stream xdr; | 3773 | struct xdr_stream xdr; |
| 3915 | struct compound_hdr hdr; | 3774 | struct compound_hdr hdr; |
| 3916 | int status; | 3775 | int status; |
| 3917 | 3776 | ||
| 3918 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 3777 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
| 3919 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 3778 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) |
| 3920 | goto out; | 3779 | goto out; |
| @@ -3944,7 +3803,7 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_link | |||
| 3944 | struct xdr_stream xdr; | 3803 | struct xdr_stream xdr; |
| 3945 | struct compound_hdr hdr; | 3804 | struct compound_hdr hdr; |
| 3946 | int status; | 3805 | int status; |
| 3947 | 3806 | ||
| 3948 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 3807 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
| 3949 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 3808 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) |
| 3950 | goto out; | 3809 | goto out; |
| @@ -3977,7 +3836,7 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_cr | |||
| 3977 | struct xdr_stream xdr; | 3836 | struct xdr_stream xdr; |
| 3978 | struct compound_hdr hdr; | 3837 | struct compound_hdr hdr; |
| 3979 | int status; | 3838 | int status; |
| 3980 | 3839 | ||
| 3981 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 3840 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
| 3982 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 3841 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) |
| 3983 | goto out; | 3842 | goto out; |
| @@ -4014,7 +3873,7 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_g | |||
| 4014 | struct xdr_stream xdr; | 3873 | struct xdr_stream xdr; |
| 4015 | struct compound_hdr hdr; | 3874 | struct compound_hdr hdr; |
| 4016 | int status; | 3875 | int status; |
| 4017 | 3876 | ||
| 4018 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 3877 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
| 4019 | status = decode_compound_hdr(&xdr, &hdr); | 3878 | status = decode_compound_hdr(&xdr, &hdr); |
| 4020 | if (status) | 3879 | if (status) |
| @@ -4025,7 +3884,6 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_g | |||
| 4025 | status = decode_getfattr(&xdr, res->fattr, res->server); | 3884 | status = decode_getfattr(&xdr, res->fattr, res->server); |
| 4026 | out: | 3885 | out: |
| 4027 | return status; | 3886 | return status; |
| 4028 | |||
| 4029 | } | 3887 | } |
| 4030 | 3888 | ||
| 4031 | /* | 3889 | /* |
| @@ -4034,21 +3892,20 @@ out: | |||
| 4034 | static int | 3892 | static int |
| 4035 | nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args) | 3893 | nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args) |
| 4036 | { | 3894 | { |
| 4037 | struct xdr_stream xdr; | 3895 | struct xdr_stream xdr; |
| 4038 | struct compound_hdr hdr = { | 3896 | struct compound_hdr hdr = { |
| 4039 | .nops = 2, | 3897 | .nops = 0, |
| 4040 | }; | 3898 | }; |
| 4041 | int status; | 3899 | int status; |
| 4042 | 3900 | ||
| 4043 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 3901 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 4044 | encode_compound_hdr(&xdr, &hdr); | 3902 | encode_compound_hdr(&xdr, &hdr); |
| 4045 | status = encode_putfh(&xdr, args->fh); | 3903 | encode_putfh(&xdr, args->fh, &hdr); |
| 4046 | if (status) | 3904 | status = encode_setacl(&xdr, args, &hdr); |
| 4047 | goto out; | 3905 | encode_nops(&hdr); |
| 4048 | status = encode_setacl(&xdr, args); | 3906 | return status; |
| 4049 | out: | ||
| 4050 | return status; | ||
| 4051 | } | 3907 | } |
| 3908 | |||
| 4052 | /* | 3909 | /* |
| 4053 | * Decode SETACL response | 3910 | * Decode SETACL response |
| 4054 | */ | 3911 | */ |
| @@ -4099,18 +3956,18 @@ out: | |||
| 4099 | */ | 3956 | */ |
| 4100 | static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res) | 3957 | static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res) |
| 4101 | { | 3958 | { |
| 4102 | struct xdr_stream xdr; | 3959 | struct xdr_stream xdr; |
| 4103 | struct compound_hdr hdr; | 3960 | struct compound_hdr hdr; |
| 4104 | int status; | 3961 | int status; |
| 4105 | 3962 | ||
| 4106 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 3963 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
| 4107 | status = decode_compound_hdr(&xdr, &hdr); | 3964 | status = decode_compound_hdr(&xdr, &hdr); |
| 4108 | if (status) | 3965 | if (status) |
| 4109 | goto out; | 3966 | goto out; |
| 4110 | status = decode_putfh(&xdr); | 3967 | status = decode_putfh(&xdr); |
| 4111 | if (status) | 3968 | if (status) |
| 4112 | goto out; | 3969 | goto out; |
| 4113 | status = decode_close(&xdr, res); | 3970 | status = decode_close(&xdr, res); |
| 4114 | if (status != 0) | 3971 | if (status != 0) |
| 4115 | goto out; | 3972 | goto out; |
| 4116 | /* | 3973 | /* |
| @@ -4121,7 +3978,7 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_clos | |||
| 4121 | */ | 3978 | */ |
| 4122 | decode_getfattr(&xdr, res->fattr, res->server); | 3979 | decode_getfattr(&xdr, res->fattr, res->server); |
| 4123 | out: | 3980 | out: |
| 4124 | return status; | 3981 | return status; |
| 4125 | } | 3982 | } |
| 4126 | 3983 | ||
| 4127 | /* | 3984 | /* |
| @@ -4129,23 +3986,23 @@ out: | |||
| 4129 | */ | 3986 | */ |
| 4130 | static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res) | 3987 | static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res) |
| 4131 | { | 3988 | { |
| 4132 | struct xdr_stream xdr; | 3989 | struct xdr_stream xdr; |
| 4133 | struct compound_hdr hdr; | 3990 | struct compound_hdr hdr; |
| 4134 | int status; | 3991 | int status; |
| 4135 | 3992 | ||
| 4136 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 3993 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
| 4137 | status = decode_compound_hdr(&xdr, &hdr); | 3994 | status = decode_compound_hdr(&xdr, &hdr); |
| 4138 | if (status) | 3995 | if (status) |
| 4139 | goto out; | 3996 | goto out; |
| 4140 | status = decode_putfh(&xdr); | 3997 | status = decode_putfh(&xdr); |
| 4141 | if (status) | 3998 | if (status) |
| 4142 | goto out; | 3999 | goto out; |
| 4143 | status = decode_savefh(&xdr); | 4000 | status = decode_savefh(&xdr); |
| 4001 | if (status) | ||
| 4002 | goto out; | ||
| 4003 | status = decode_open(&xdr, res); | ||
| 4144 | if (status) | 4004 | if (status) |
| 4145 | goto out; | 4005 | goto out; |
| 4146 | status = decode_open(&xdr, res); | ||
| 4147 | if (status) | ||
| 4148 | goto out; | ||
| 4149 | if (decode_getfh(&xdr, &res->fh) != 0) | 4006 | if (decode_getfh(&xdr, &res->fh) != 0) |
| 4150 | goto out; | 4007 | goto out; |
| 4151 | if (decode_getfattr(&xdr, res->f_attr, res->server) != 0) | 4008 | if (decode_getfattr(&xdr, res->f_attr, res->server) != 0) |
| @@ -4154,7 +4011,7 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openr | |||
| 4154 | goto out; | 4011 | goto out; |
| 4155 | decode_getfattr(&xdr, res->dir_attr, res->server); | 4012 | decode_getfattr(&xdr, res->dir_attr, res->server); |
| 4156 | out: | 4013 | out: |
| 4157 | return status; | 4014 | return status; |
| 4158 | } | 4015 | } |
| 4159 | 4016 | ||
| 4160 | /* | 4017 | /* |
| @@ -4162,20 +4019,20 @@ out: | |||
| 4162 | */ | 4019 | */ |
| 4163 | static int nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, __be32 *p, struct nfs_open_confirmres *res) | 4020 | static int nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, __be32 *p, struct nfs_open_confirmres *res) |
| 4164 | { | 4021 | { |
| 4165 | struct xdr_stream xdr; | 4022 | struct xdr_stream xdr; |
| 4166 | struct compound_hdr hdr; | 4023 | struct compound_hdr hdr; |
| 4167 | int status; | 4024 | int status; |
| 4168 | 4025 | ||
| 4169 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4026 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
| 4170 | status = decode_compound_hdr(&xdr, &hdr); | 4027 | status = decode_compound_hdr(&xdr, &hdr); |
| 4171 | if (status) | 4028 | if (status) |
| 4172 | goto out; | 4029 | goto out; |
| 4173 | status = decode_putfh(&xdr); | 4030 | status = decode_putfh(&xdr); |
| 4174 | if (status) | 4031 | if (status) |
| 4175 | goto out; | 4032 | goto out; |
| 4176 | status = decode_open_confirm(&xdr, res); | 4033 | status = decode_open_confirm(&xdr, res); |
| 4177 | out: | 4034 | out: |
| 4178 | return status; | 4035 | return status; |
| 4179 | } | 4036 | } |
| 4180 | 4037 | ||
| 4181 | /* | 4038 | /* |
| @@ -4183,23 +4040,23 @@ out: | |||
| 4183 | */ | 4040 | */ |
| 4184 | static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res) | 4041 | static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res) |
| 4185 | { | 4042 | { |
| 4186 | struct xdr_stream xdr; | 4043 | struct xdr_stream xdr; |
| 4187 | struct compound_hdr hdr; | 4044 | struct compound_hdr hdr; |
| 4188 | int status; | 4045 | int status; |
| 4189 | 4046 | ||
| 4190 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4047 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
| 4191 | status = decode_compound_hdr(&xdr, &hdr); | 4048 | status = decode_compound_hdr(&xdr, &hdr); |
| 4192 | if (status) | 4049 | if (status) |
| 4193 | goto out; | 4050 | goto out; |
| 4194 | status = decode_putfh(&xdr); | 4051 | status = decode_putfh(&xdr); |
| 4195 | if (status) | 4052 | if (status) |
| 4196 | goto out; | 4053 | goto out; |
| 4197 | status = decode_open(&xdr, res); | 4054 | status = decode_open(&xdr, res); |
| 4198 | if (status) | 4055 | if (status) |
| 4199 | goto out; | 4056 | goto out; |
| 4200 | decode_getfattr(&xdr, res->f_attr, res->server); | 4057 | decode_getfattr(&xdr, res->f_attr, res->server); |
| 4201 | out: | 4058 | out: |
| 4202 | return status; | 4059 | return status; |
| 4203 | } | 4060 | } |
| 4204 | 4061 | ||
| 4205 | /* | 4062 | /* |
| @@ -4207,25 +4064,25 @@ out: | |||
| 4207 | */ | 4064 | */ |
| 4208 | static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_setattrres *res) | 4065 | static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_setattrres *res) |
| 4209 | { | 4066 | { |
| 4210 | struct xdr_stream xdr; | 4067 | struct xdr_stream xdr; |
| 4211 | struct compound_hdr hdr; | 4068 | struct compound_hdr hdr; |
| 4212 | int status; | 4069 | int status; |
| 4213 | 4070 | ||
| 4214 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4071 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
| 4215 | status = decode_compound_hdr(&xdr, &hdr); | 4072 | status = decode_compound_hdr(&xdr, &hdr); |
| 4216 | if (status) | 4073 | if (status) |
| 4217 | goto out; | 4074 | goto out; |
| 4218 | status = decode_putfh(&xdr); | 4075 | status = decode_putfh(&xdr); |
| 4219 | if (status) | 4076 | if (status) |
| 4220 | goto out; | 4077 | goto out; |
| 4221 | status = decode_setattr(&xdr, res); | 4078 | status = decode_setattr(&xdr, res); |
| 4222 | if (status) | 4079 | if (status) |
| 4223 | goto out; | 4080 | goto out; |
| 4224 | status = decode_getfattr(&xdr, res->fattr, res->server); | 4081 | status = decode_getfattr(&xdr, res->fattr, res->server); |
| 4225 | if (status == NFS4ERR_DELAY) | 4082 | if (status == NFS4ERR_DELAY) |
| 4226 | status = 0; | 4083 | status = 0; |
| 4227 | out: | 4084 | out: |
| 4228 | return status; | 4085 | return status; |
| 4229 | } | 4086 | } |
| 4230 | 4087 | ||
| 4231 | /* | 4088 | /* |
| @@ -4421,8 +4278,6 @@ static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs_fsinf | |||
| 4421 | status = decode_putfh(&xdr); | 4278 | status = decode_putfh(&xdr); |
| 4422 | if (!status) | 4279 | if (!status) |
| 4423 | status = decode_fsinfo(&xdr, fsinfo); | 4280 | status = decode_fsinfo(&xdr, fsinfo); |
| 4424 | if (!status) | ||
| 4425 | status = nfs4_stat_to_errno(hdr.status); | ||
| 4426 | return status; | 4281 | return status; |
| 4427 | } | 4282 | } |
| 4428 | 4283 | ||
| @@ -4511,8 +4366,6 @@ static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p, | |||
| 4511 | status = decode_compound_hdr(&xdr, &hdr); | 4366 | status = decode_compound_hdr(&xdr, &hdr); |
| 4512 | if (!status) | 4367 | if (!status) |
| 4513 | status = decode_setclientid(&xdr, clp); | 4368 | status = decode_setclientid(&xdr, clp); |
| 4514 | if (!status) | ||
| 4515 | status = nfs4_stat_to_errno(hdr.status); | ||
| 4516 | return status; | 4369 | return status; |
| 4517 | } | 4370 | } |
| 4518 | 4371 | ||
| @@ -4533,8 +4386,6 @@ static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, __be32 *p, str | |||
| 4533 | status = decode_putrootfh(&xdr); | 4386 | status = decode_putrootfh(&xdr); |
| 4534 | if (!status) | 4387 | if (!status) |
| 4535 | status = decode_fsinfo(&xdr, fsinfo); | 4388 | status = decode_fsinfo(&xdr, fsinfo); |
| 4536 | if (!status) | ||
| 4537 | status = nfs4_stat_to_errno(hdr.status); | ||
| 4538 | return status; | 4389 | return status; |
| 4539 | } | 4390 | } |
| 4540 | 4391 | ||
| @@ -4715,7 +4566,7 @@ nfs4_stat_to_errno(int stat) | |||
| 4715 | .p_replen = NFS4_##restype##_sz, \ | 4566 | .p_replen = NFS4_##restype##_sz, \ |
| 4716 | .p_statidx = NFSPROC4_CLNT_##proc, \ | 4567 | .p_statidx = NFSPROC4_CLNT_##proc, \ |
| 4717 | .p_name = #proc, \ | 4568 | .p_name = #proc, \ |
| 4718 | } | 4569 | } |
| 4719 | 4570 | ||
| 4720 | struct rpc_procinfo nfs4_procedures[] = { | 4571 | struct rpc_procinfo nfs4_procedures[] = { |
| 4721 | PROC(READ, enc_read, dec_read), | 4572 | PROC(READ, enc_read, dec_read), |
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index d74d16ce0d49..d9ef602fbc5a 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c | |||
| @@ -86,6 +86,8 @@ | |||
| 86 | #include <net/ipconfig.h> | 86 | #include <net/ipconfig.h> |
| 87 | #include <linux/parser.h> | 87 | #include <linux/parser.h> |
| 88 | 88 | ||
| 89 | #include "internal.h" | ||
| 90 | |||
| 89 | /* Define this to allow debugging output */ | 91 | /* Define this to allow debugging output */ |
| 90 | #undef NFSROOT_DEBUG | 92 | #undef NFSROOT_DEBUG |
| 91 | #define NFSDBG_FACILITY NFSDBG_ROOT | 93 | #define NFSDBG_FACILITY NFSDBG_ROOT |
| @@ -100,7 +102,7 @@ static char nfs_root_name[256] __initdata = ""; | |||
| 100 | static __be32 servaddr __initdata = 0; | 102 | static __be32 servaddr __initdata = 0; |
| 101 | 103 | ||
| 102 | /* Name of directory to mount */ | 104 | /* Name of directory to mount */ |
| 103 | static char nfs_path[NFS_MAXPATHLEN] __initdata = { 0, }; | 105 | static char nfs_export_path[NFS_MAXPATHLEN] __initdata = { 0, }; |
| 104 | 106 | ||
| 105 | /* NFS-related data */ | 107 | /* NFS-related data */ |
| 106 | static struct nfs_mount_data nfs_data __initdata = { 0, };/* NFS mount info */ | 108 | static struct nfs_mount_data nfs_data __initdata = { 0, };/* NFS mount info */ |
| @@ -312,7 +314,7 @@ static int __init root_nfs_name(char *name) | |||
| 312 | printk(KERN_ERR "Root-NFS: Pathname for remote directory too long.\n"); | 314 | printk(KERN_ERR "Root-NFS: Pathname for remote directory too long.\n"); |
| 313 | return -1; | 315 | return -1; |
| 314 | } | 316 | } |
| 315 | sprintf(nfs_path, buf, cp); | 317 | sprintf(nfs_export_path, buf, cp); |
| 316 | 318 | ||
| 317 | return 1; | 319 | return 1; |
| 318 | } | 320 | } |
| @@ -340,7 +342,7 @@ static int __init root_nfs_addr(void) | |||
| 340 | static void __init root_nfs_print(void) | 342 | static void __init root_nfs_print(void) |
| 341 | { | 343 | { |
| 342 | printk(KERN_NOTICE "Root-NFS: Mounting %s on server %s as root\n", | 344 | printk(KERN_NOTICE "Root-NFS: Mounting %s on server %s as root\n", |
| 343 | nfs_path, nfs_data.hostname); | 345 | nfs_export_path, nfs_data.hostname); |
| 344 | printk(KERN_NOTICE "Root-NFS: rsize = %d, wsize = %d, timeo = %d, retrans = %d\n", | 346 | printk(KERN_NOTICE "Root-NFS: rsize = %d, wsize = %d, timeo = %d, retrans = %d\n", |
| 345 | nfs_data.rsize, nfs_data.wsize, nfs_data.timeo, nfs_data.retrans); | 347 | nfs_data.rsize, nfs_data.wsize, nfs_data.timeo, nfs_data.retrans); |
| 346 | printk(KERN_NOTICE "Root-NFS: acreg (min,max) = (%d,%d), acdir (min,max) = (%d,%d)\n", | 348 | printk(KERN_NOTICE "Root-NFS: acreg (min,max) = (%d,%d), acdir (min,max) = (%d,%d)\n", |
| @@ -485,18 +487,23 @@ static int __init root_nfs_get_handle(void) | |||
| 485 | { | 487 | { |
| 486 | struct nfs_fh fh; | 488 | struct nfs_fh fh; |
| 487 | struct sockaddr_in sin; | 489 | struct sockaddr_in sin; |
| 490 | struct nfs_mount_request request = { | ||
| 491 | .sap = (struct sockaddr *)&sin, | ||
| 492 | .salen = sizeof(sin), | ||
| 493 | .dirpath = nfs_export_path, | ||
| 494 | .version = (nfs_data.flags & NFS_MOUNT_VER3) ? | ||
| 495 | NFS_MNT3_VERSION : NFS_MNT_VERSION, | ||
| 496 | .protocol = (nfs_data.flags & NFS_MOUNT_TCP) ? | ||
| 497 | XPRT_TRANSPORT_TCP : XPRT_TRANSPORT_UDP, | ||
| 498 | .fh = &fh, | ||
| 499 | }; | ||
| 488 | int status; | 500 | int status; |
| 489 | int protocol = (nfs_data.flags & NFS_MOUNT_TCP) ? | ||
| 490 | XPRT_TRANSPORT_TCP : XPRT_TRANSPORT_UDP; | ||
| 491 | int version = (nfs_data.flags & NFS_MOUNT_VER3) ? | ||
| 492 | NFS_MNT3_VERSION : NFS_MNT_VERSION; | ||
| 493 | 501 | ||
| 494 | set_sockaddr(&sin, servaddr, htons(mount_port)); | 502 | set_sockaddr(&sin, servaddr, htons(mount_port)); |
| 495 | status = nfs_mount((struct sockaddr *) &sin, sizeof(sin), NULL, | 503 | status = nfs_mount(&request); |
| 496 | nfs_path, version, protocol, &fh); | ||
| 497 | if (status < 0) | 504 | if (status < 0) |
| 498 | printk(KERN_ERR "Root-NFS: Server returned error %d " | 505 | printk(KERN_ERR "Root-NFS: Server returned error %d " |
| 499 | "while mounting %s\n", status, nfs_path); | 506 | "while mounting %s\n", status, nfs_export_path); |
| 500 | else { | 507 | else { |
| 501 | nfs_data.root.size = fh.size; | 508 | nfs_data.root.size = fh.size; |
| 502 | memcpy(nfs_data.root.data, fh.data, fh.size); | 509 | memcpy(nfs_data.root.data, fh.data, fh.size); |
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 40d17987d0e8..f856004bb7fa 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
| @@ -533,12 +533,6 @@ readpage_async_filler(void *data, struct page *page) | |||
| 533 | unsigned int len; | 533 | unsigned int len; |
| 534 | int error; | 534 | int error; |
| 535 | 535 | ||
| 536 | error = nfs_wb_page(inode, page); | ||
| 537 | if (error) | ||
| 538 | goto out_unlock; | ||
| 539 | if (PageUptodate(page)) | ||
| 540 | goto out_unlock; | ||
| 541 | |||
| 542 | len = nfs_page_length(page); | 536 | len = nfs_page_length(page); |
| 543 | if (len == 0) | 537 | if (len == 0) |
| 544 | return nfs_return_empty_page(page); | 538 | return nfs_return_empty_page(page); |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index bb0313ac9e1f..d6686f4786dc 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
| @@ -75,6 +75,7 @@ enum { | |||
| 75 | Opt_acl, Opt_noacl, | 75 | Opt_acl, Opt_noacl, |
| 76 | Opt_rdirplus, Opt_nordirplus, | 76 | Opt_rdirplus, Opt_nordirplus, |
| 77 | Opt_sharecache, Opt_nosharecache, | 77 | Opt_sharecache, Opt_nosharecache, |
| 78 | Opt_resvport, Opt_noresvport, | ||
| 78 | 79 | ||
| 79 | /* Mount options that take integer arguments */ | 80 | /* Mount options that take integer arguments */ |
| 80 | Opt_port, | 81 | Opt_port, |
| @@ -129,6 +130,8 @@ static const match_table_t nfs_mount_option_tokens = { | |||
| 129 | { Opt_nordirplus, "nordirplus" }, | 130 | { Opt_nordirplus, "nordirplus" }, |
| 130 | { Opt_sharecache, "sharecache" }, | 131 | { Opt_sharecache, "sharecache" }, |
| 131 | { Opt_nosharecache, "nosharecache" }, | 132 | { Opt_nosharecache, "nosharecache" }, |
| 133 | { Opt_resvport, "resvport" }, | ||
| 134 | { Opt_noresvport, "noresvport" }, | ||
| 132 | 135 | ||
| 133 | { Opt_port, "port=%u" }, | 136 | { Opt_port, "port=%u" }, |
| 134 | { Opt_rsize, "rsize=%u" }, | 137 | { Opt_rsize, "rsize=%u" }, |
| @@ -512,7 +515,8 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
| 512 | { NFS_MOUNT_NONLM, ",nolock", "" }, | 515 | { NFS_MOUNT_NONLM, ",nolock", "" }, |
| 513 | { NFS_MOUNT_NOACL, ",noacl", "" }, | 516 | { NFS_MOUNT_NOACL, ",noacl", "" }, |
| 514 | { NFS_MOUNT_NORDIRPLUS, ",nordirplus", "" }, | 517 | { NFS_MOUNT_NORDIRPLUS, ",nordirplus", "" }, |
| 515 | { NFS_MOUNT_UNSHARED, ",nosharecache", ""}, | 518 | { NFS_MOUNT_UNSHARED, ",nosharecache", "" }, |
| 519 | { NFS_MOUNT_NORESVPORT, ",noresvport", "" }, | ||
| 516 | { 0, NULL, NULL } | 520 | { 0, NULL, NULL } |
| 517 | }; | 521 | }; |
| 518 | const struct proc_nfs_info *nfs_infop; | 522 | const struct proc_nfs_info *nfs_infop; |
| @@ -1033,6 +1037,12 @@ static int nfs_parse_mount_options(char *raw, | |||
| 1033 | case Opt_nosharecache: | 1037 | case Opt_nosharecache: |
| 1034 | mnt->flags |= NFS_MOUNT_UNSHARED; | 1038 | mnt->flags |= NFS_MOUNT_UNSHARED; |
| 1035 | break; | 1039 | break; |
| 1040 | case Opt_resvport: | ||
| 1041 | mnt->flags &= ~NFS_MOUNT_NORESVPORT; | ||
| 1042 | break; | ||
| 1043 | case Opt_noresvport: | ||
| 1044 | mnt->flags |= NFS_MOUNT_NORESVPORT; | ||
| 1045 | break; | ||
| 1036 | 1046 | ||
| 1037 | /* | 1047 | /* |
| 1038 | * options that take numeric values | 1048 | * options that take numeric values |
| @@ -1327,8 +1337,14 @@ out_security_failure: | |||
| 1327 | static int nfs_try_mount(struct nfs_parsed_mount_data *args, | 1337 | static int nfs_try_mount(struct nfs_parsed_mount_data *args, |
| 1328 | struct nfs_fh *root_fh) | 1338 | struct nfs_fh *root_fh) |
| 1329 | { | 1339 | { |
| 1330 | struct sockaddr *sap = (struct sockaddr *)&args->mount_server.address; | 1340 | struct nfs_mount_request request = { |
| 1331 | char *hostname; | 1341 | .sap = (struct sockaddr *) |
| 1342 | &args->mount_server.address, | ||
| 1343 | .dirpath = args->nfs_server.export_path, | ||
| 1344 | .protocol = args->mount_server.protocol, | ||
| 1345 | .fh = root_fh, | ||
| 1346 | .noresvport = args->flags & NFS_MOUNT_NORESVPORT, | ||
| 1347 | }; | ||
| 1332 | int status; | 1348 | int status; |
| 1333 | 1349 | ||
| 1334 | if (args->mount_server.version == 0) { | 1350 | if (args->mount_server.version == 0) { |
| @@ -1337,42 +1353,38 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, | |||
| 1337 | else | 1353 | else |
| 1338 | args->mount_server.version = NFS_MNT_VERSION; | 1354 | args->mount_server.version = NFS_MNT_VERSION; |
| 1339 | } | 1355 | } |
| 1356 | request.version = args->mount_server.version; | ||
| 1340 | 1357 | ||
| 1341 | if (args->mount_server.hostname) | 1358 | if (args->mount_server.hostname) |
| 1342 | hostname = args->mount_server.hostname; | 1359 | request.hostname = args->mount_server.hostname; |
| 1343 | else | 1360 | else |
| 1344 | hostname = args->nfs_server.hostname; | 1361 | request.hostname = args->nfs_server.hostname; |
| 1345 | 1362 | ||
| 1346 | /* | 1363 | /* |
| 1347 | * Construct the mount server's address. | 1364 | * Construct the mount server's address. |
| 1348 | */ | 1365 | */ |
| 1349 | if (args->mount_server.address.ss_family == AF_UNSPEC) { | 1366 | if (args->mount_server.address.ss_family == AF_UNSPEC) { |
| 1350 | memcpy(sap, &args->nfs_server.address, | 1367 | memcpy(request.sap, &args->nfs_server.address, |
| 1351 | args->nfs_server.addrlen); | 1368 | args->nfs_server.addrlen); |
| 1352 | args->mount_server.addrlen = args->nfs_server.addrlen; | 1369 | args->mount_server.addrlen = args->nfs_server.addrlen; |
| 1353 | } | 1370 | } |
| 1371 | request.salen = args->mount_server.addrlen; | ||
| 1354 | 1372 | ||
| 1355 | /* | 1373 | /* |
| 1356 | * autobind will be used if mount_server.port == 0 | 1374 | * autobind will be used if mount_server.port == 0 |
| 1357 | */ | 1375 | */ |
| 1358 | nfs_set_port(sap, args->mount_server.port); | 1376 | nfs_set_port(request.sap, args->mount_server.port); |
| 1359 | 1377 | ||
| 1360 | /* | 1378 | /* |
| 1361 | * Now ask the mount server to map our export path | 1379 | * Now ask the mount server to map our export path |
| 1362 | * to a file handle. | 1380 | * to a file handle. |
| 1363 | */ | 1381 | */ |
| 1364 | status = nfs_mount(sap, | 1382 | status = nfs_mount(&request); |
| 1365 | args->mount_server.addrlen, | ||
| 1366 | hostname, | ||
| 1367 | args->nfs_server.export_path, | ||
| 1368 | args->mount_server.version, | ||
| 1369 | args->mount_server.protocol, | ||
| 1370 | root_fh); | ||
| 1371 | if (status == 0) | 1383 | if (status == 0) |
| 1372 | return 0; | 1384 | return 0; |
| 1373 | 1385 | ||
| 1374 | dfprintk(MOUNT, "NFS: unable to mount server %s, error %d\n", | 1386 | dfprintk(MOUNT, "NFS: unable to mount server %s, error %d\n", |
| 1375 | hostname, status); | 1387 | request.hostname, status); |
| 1376 | return status; | 1388 | return status; |
| 1377 | } | 1389 | } |
| 1378 | 1390 | ||
| @@ -2419,7 +2431,7 @@ static void nfs4_kill_super(struct super_block *sb) | |||
| 2419 | { | 2431 | { |
| 2420 | struct nfs_server *server = NFS_SB(sb); | 2432 | struct nfs_server *server = NFS_SB(sb); |
| 2421 | 2433 | ||
| 2422 | nfs_return_all_delegations(sb); | 2434 | nfs_super_return_all_delegations(sb); |
| 2423 | kill_anon_super(sb); | 2435 | kill_anon_super(sb); |
| 2424 | 2436 | ||
| 2425 | nfs4_renewd_prepare_shutdown(server); | 2437 | nfs4_renewd_prepare_shutdown(server); |
diff --git a/fs/nfs_common/nfsacl.c b/fs/nfs_common/nfsacl.c index c11f5375d7c1..04133aacb1e5 100644 --- a/fs/nfs_common/nfsacl.c +++ b/fs/nfs_common/nfsacl.c | |||
| @@ -29,8 +29,8 @@ | |||
| 29 | 29 | ||
| 30 | MODULE_LICENSE("GPL"); | 30 | MODULE_LICENSE("GPL"); |
| 31 | 31 | ||
| 32 | EXPORT_SYMBOL(nfsacl_encode); | 32 | EXPORT_SYMBOL_GPL(nfsacl_encode); |
| 33 | EXPORT_SYMBOL(nfsacl_decode); | 33 | EXPORT_SYMBOL_GPL(nfsacl_decode); |
| 34 | 34 | ||
| 35 | struct nfsacl_encode_desc { | 35 | struct nfsacl_encode_desc { |
| 36 | struct xdr_array2_desc desc; | 36 | struct xdr_array2_desc desc; |
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 094747a1227c..6d7d8c02c197 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
| @@ -358,6 +358,7 @@ static struct rpc_program cb_program = { | |||
| 358 | .nrvers = ARRAY_SIZE(nfs_cb_version), | 358 | .nrvers = ARRAY_SIZE(nfs_cb_version), |
| 359 | .version = nfs_cb_version, | 359 | .version = nfs_cb_version, |
| 360 | .stats = &cb_stats, | 360 | .stats = &cb_stats, |
| 361 | .pipe_dir_name = "/nfsd4_cb", | ||
| 361 | }; | 362 | }; |
| 362 | 363 | ||
| 363 | /* Reference counting, callback cleanup, etc., all look racy as heck. | 364 | /* Reference counting, callback cleanup, etc., all look racy as heck. |
| @@ -382,8 +383,9 @@ static int do_probe_callback(void *data) | |||
| 382 | .program = &cb_program, | 383 | .program = &cb_program, |
| 383 | .prognumber = cb->cb_prog, | 384 | .prognumber = cb->cb_prog, |
| 384 | .version = nfs_cb_version[1]->number, | 385 | .version = nfs_cb_version[1]->number, |
| 385 | .authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */ | 386 | .authflavor = clp->cl_flavor, |
| 386 | .flags = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET), | 387 | .flags = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET), |
| 388 | .client_name = clp->cl_principal, | ||
| 387 | }; | 389 | }; |
| 388 | struct rpc_message msg = { | 390 | struct rpc_message msg = { |
| 389 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], | 391 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], |
| @@ -392,6 +394,11 @@ static int do_probe_callback(void *data) | |||
| 392 | struct rpc_clnt *client; | 394 | struct rpc_clnt *client; |
| 393 | int status; | 395 | int status; |
| 394 | 396 | ||
| 397 | if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5)) { | ||
| 398 | status = nfserr_cb_path_down; | ||
| 399 | goto out_err; | ||
| 400 | } | ||
| 401 | |||
| 395 | /* Initialize address */ | 402 | /* Initialize address */ |
| 396 | memset(&addr, 0, sizeof(addr)); | 403 | memset(&addr, 0, sizeof(addr)); |
| 397 | addr.sin_family = AF_INET; | 404 | addr.sin_family = AF_INET; |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index bf4cd46a5a11..13e0e074dbb8 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
| @@ -54,6 +54,7 @@ | |||
| 54 | #include <linux/mutex.h> | 54 | #include <linux/mutex.h> |
| 55 | #include <linux/lockd/bind.h> | 55 | #include <linux/lockd/bind.h> |
| 56 | #include <linux/module.h> | 56 | #include <linux/module.h> |
| 57 | #include <linux/sunrpc/svcauth_gss.h> | ||
| 57 | 58 | ||
| 58 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 59 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
| 59 | 60 | ||
| @@ -377,6 +378,7 @@ free_client(struct nfs4_client *clp) | |||
| 377 | shutdown_callback_client(clp); | 378 | shutdown_callback_client(clp); |
| 378 | if (clp->cl_cred.cr_group_info) | 379 | if (clp->cl_cred.cr_group_info) |
| 379 | put_group_info(clp->cl_cred.cr_group_info); | 380 | put_group_info(clp->cl_cred.cr_group_info); |
| 381 | kfree(clp->cl_principal); | ||
| 380 | kfree(clp->cl_name.data); | 382 | kfree(clp->cl_name.data); |
| 381 | kfree(clp); | 383 | kfree(clp); |
| 382 | } | 384 | } |
| @@ -696,6 +698,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 696 | unsigned int strhashval; | 698 | unsigned int strhashval; |
| 697 | struct nfs4_client *conf, *unconf, *new; | 699 | struct nfs4_client *conf, *unconf, *new; |
| 698 | __be32 status; | 700 | __be32 status; |
| 701 | char *princ; | ||
| 699 | char dname[HEXDIR_LEN]; | 702 | char dname[HEXDIR_LEN]; |
| 700 | 703 | ||
| 701 | if (!check_name(clname)) | 704 | if (!check_name(clname)) |
| @@ -783,6 +786,15 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 783 | } | 786 | } |
| 784 | copy_verf(new, &clverifier); | 787 | copy_verf(new, &clverifier); |
| 785 | new->cl_addr = sin->sin_addr.s_addr; | 788 | new->cl_addr = sin->sin_addr.s_addr; |
| 789 | new->cl_flavor = rqstp->rq_flavor; | ||
| 790 | princ = svc_gss_principal(rqstp); | ||
| 791 | if (princ) { | ||
| 792 | new->cl_principal = kstrdup(princ, GFP_KERNEL); | ||
| 793 | if (new->cl_principal == NULL) { | ||
| 794 | free_client(new); | ||
| 795 | goto out; | ||
| 796 | } | ||
| 797 | } | ||
| 786 | copy_cred(&new->cl_cred, &rqstp->rq_cred); | 798 | copy_cred(&new->cl_cred, &rqstp->rq_cred); |
| 787 | gen_confirm(new); | 799 | gen_confirm(new); |
| 788 | gen_callback(new, setclid); | 800 | gen_callback(new, setclid); |
diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h index abb6ac639e8e..1a9cf78bfce5 100644 --- a/include/linux/jiffies.h +++ b/include/linux/jiffies.h | |||
| @@ -115,10 +115,20 @@ static inline u64 get_jiffies_64(void) | |||
| 115 | ((long)(a) - (long)(b) >= 0)) | 115 | ((long)(a) - (long)(b) >= 0)) |
| 116 | #define time_before_eq(a,b) time_after_eq(b,a) | 116 | #define time_before_eq(a,b) time_after_eq(b,a) |
| 117 | 117 | ||
| 118 | /* | ||
| 119 | * Calculate whether a is in the range of [b, c]. | ||
| 120 | */ | ||
| 118 | #define time_in_range(a,b,c) \ | 121 | #define time_in_range(a,b,c) \ |
| 119 | (time_after_eq(a,b) && \ | 122 | (time_after_eq(a,b) && \ |
| 120 | time_before_eq(a,c)) | 123 | time_before_eq(a,c)) |
| 121 | 124 | ||
| 125 | /* | ||
| 126 | * Calculate whether a is in the range of [b, c). | ||
| 127 | */ | ||
| 128 | #define time_in_range_open(a,b,c) \ | ||
| 129 | (time_after_eq(a,b) && \ | ||
| 130 | time_before(a,c)) | ||
| 131 | |||
| 122 | /* Same as above, but does so with platform independent 64bit types. | 132 | /* Same as above, but does so with platform independent 64bit types. |
| 123 | * These must be used when utilizing jiffies_64 (i.e. return value of | 133 | * These must be used when utilizing jiffies_64 (i.e. return value of |
| 124 | * get_jiffies_64() */ | 134 | * get_jiffies_64() */ |
diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h index e5872dc994c0..fbc48f898521 100644 --- a/include/linux/lockd/bind.h +++ b/include/linux/lockd/bind.h | |||
| @@ -41,6 +41,7 @@ struct nlmclnt_initdata { | |||
| 41 | size_t addrlen; | 41 | size_t addrlen; |
| 42 | unsigned short protocol; | 42 | unsigned short protocol; |
| 43 | u32 nfs_version; | 43 | u32 nfs_version; |
| 44 | int noresvport; | ||
| 44 | }; | 45 | }; |
| 45 | 46 | ||
| 46 | /* | 47 | /* |
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index b56d5aa9b194..23da3fa69efa 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h | |||
| @@ -49,6 +49,7 @@ struct nlm_host { | |||
| 49 | unsigned short h_proto; /* transport proto */ | 49 | unsigned short h_proto; /* transport proto */ |
| 50 | unsigned short h_reclaiming : 1, | 50 | unsigned short h_reclaiming : 1, |
| 51 | h_server : 1, /* server side, not client side */ | 51 | h_server : 1, /* server side, not client side */ |
| 52 | h_noresvport : 1, | ||
| 52 | h_inuse : 1; | 53 | h_inuse : 1; |
| 53 | wait_queue_head_t h_gracewait; /* wait while reclaiming */ | 54 | wait_queue_head_t h_gracewait; /* wait while reclaiming */ |
| 54 | struct rw_semaphore h_rwsem; /* Reboot recovery lock */ | 55 | struct rw_semaphore h_rwsem; /* Reboot recovery lock */ |
| @@ -220,7 +221,8 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap, | |||
| 220 | const size_t salen, | 221 | const size_t salen, |
| 221 | const unsigned short protocol, | 222 | const unsigned short protocol, |
| 222 | const u32 version, | 223 | const u32 version, |
| 223 | const char *hostname); | 224 | const char *hostname, |
| 225 | int noresvport); | ||
| 224 | struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp, | 226 | struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp, |
| 225 | const char *hostname, | 227 | const char *hostname, |
| 226 | const size_t hostname_len); | 228 | const size_t hostname_len); |
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 4eaa8347a0d9..db867b04ac3c 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
| @@ -83,7 +83,7 @@ struct nfs_open_context { | |||
| 83 | struct rpc_cred *cred; | 83 | struct rpc_cred *cred; |
| 84 | struct nfs4_state *state; | 84 | struct nfs4_state *state; |
| 85 | fl_owner_t lockowner; | 85 | fl_owner_t lockowner; |
| 86 | int mode; | 86 | fmode_t mode; |
| 87 | 87 | ||
| 88 | unsigned long flags; | 88 | unsigned long flags; |
| 89 | #define NFS_CONTEXT_ERROR_WRITE (0) | 89 | #define NFS_CONTEXT_ERROR_WRITE (0) |
| @@ -130,7 +130,10 @@ struct nfs_inode { | |||
| 130 | * | 130 | * |
| 131 | * We need to revalidate the cached attrs for this inode if | 131 | * We need to revalidate the cached attrs for this inode if |
| 132 | * | 132 | * |
| 133 | * jiffies - read_cache_jiffies > attrtimeo | 133 | * jiffies - read_cache_jiffies >= attrtimeo |
| 134 | * | ||
| 135 | * Please note the comparison is greater than or equal | ||
| 136 | * so that zero timeout values can be specified. | ||
| 134 | */ | 137 | */ |
| 135 | unsigned long read_cache_jiffies; | 138 | unsigned long read_cache_jiffies; |
| 136 | unsigned long attrtimeo; | 139 | unsigned long attrtimeo; |
| @@ -180,7 +183,7 @@ struct nfs_inode { | |||
| 180 | /* NFSv4 state */ | 183 | /* NFSv4 state */ |
| 181 | struct list_head open_states; | 184 | struct list_head open_states; |
| 182 | struct nfs_delegation *delegation; | 185 | struct nfs_delegation *delegation; |
| 183 | int delegation_state; | 186 | fmode_t delegation_state; |
| 184 | struct rw_semaphore rwsem; | 187 | struct rw_semaphore rwsem; |
| 185 | #endif /* CONFIG_NFS_V4*/ | 188 | #endif /* CONFIG_NFS_V4*/ |
| 186 | struct inode vfs_inode; | 189 | struct inode vfs_inode; |
| @@ -342,7 +345,7 @@ extern int nfs_setattr(struct dentry *, struct iattr *); | |||
| 342 | extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr); | 345 | extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr); |
| 343 | extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx); | 346 | extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx); |
| 344 | extern void put_nfs_open_context(struct nfs_open_context *ctx); | 347 | extern void put_nfs_open_context(struct nfs_open_context *ctx); |
| 345 | extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, int mode); | 348 | extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, fmode_t mode); |
| 346 | extern u64 nfs_compat_user_ino64(u64 fileid); | 349 | extern u64 nfs_compat_user_ino64(u64 fileid); |
| 347 | extern void nfs_fattr_init(struct nfs_fattr *fattr); | 350 | extern void nfs_fattr_init(struct nfs_fattr *fattr); |
| 348 | 351 | ||
| @@ -533,12 +536,6 @@ static inline void nfs3_forget_cached_acls(struct inode *inode) | |||
| 533 | #endif /* CONFIG_NFS_V3_ACL */ | 536 | #endif /* CONFIG_NFS_V3_ACL */ |
| 534 | 537 | ||
| 535 | /* | 538 | /* |
| 536 | * linux/fs/mount_clnt.c | ||
| 537 | */ | ||
| 538 | extern int nfs_mount(struct sockaddr *, size_t, char *, char *, | ||
| 539 | int, int, struct nfs_fh *); | ||
| 540 | |||
| 541 | /* | ||
| 542 | * inline functions | 539 | * inline functions |
| 543 | */ | 540 | */ |
| 544 | 541 | ||
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 4e477ae58699..9bb81aec91cf 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h | |||
| @@ -42,12 +42,6 @@ struct nfs_client { | |||
| 42 | struct rb_root cl_openowner_id; | 42 | struct rb_root cl_openowner_id; |
| 43 | struct rb_root cl_lockowner_id; | 43 | struct rb_root cl_lockowner_id; |
| 44 | 44 | ||
| 45 | /* | ||
| 46 | * The following rwsem ensures exclusive access to the server | ||
| 47 | * while we recover the state following a lease expiration. | ||
| 48 | */ | ||
| 49 | struct rw_semaphore cl_sem; | ||
| 50 | |||
| 51 | struct list_head cl_delegations; | 45 | struct list_head cl_delegations; |
| 52 | struct rb_root cl_state_owners; | 46 | struct rb_root cl_state_owners; |
| 53 | spinlock_t cl_lock; | 47 | spinlock_t cl_lock; |
diff --git a/include/linux/nfs_mount.h b/include/linux/nfs_mount.h index 6549a06ac16e..4499016e6d0d 100644 --- a/include/linux/nfs_mount.h +++ b/include/linux/nfs_mount.h | |||
| @@ -45,7 +45,7 @@ struct nfs_mount_data { | |||
| 45 | char context[NFS_MAX_CONTEXT_LEN + 1]; /* 6 */ | 45 | char context[NFS_MAX_CONTEXT_LEN + 1]; /* 6 */ |
| 46 | }; | 46 | }; |
| 47 | 47 | ||
| 48 | /* bits in the flags field */ | 48 | /* bits in the flags field visible to user space */ |
| 49 | 49 | ||
| 50 | #define NFS_MOUNT_SOFT 0x0001 /* 1 */ | 50 | #define NFS_MOUNT_SOFT 0x0001 /* 1 */ |
| 51 | #define NFS_MOUNT_INTR 0x0002 /* 1 */ /* now unused, but ABI */ | 51 | #define NFS_MOUNT_INTR 0x0002 /* 1 */ /* now unused, but ABI */ |
| @@ -68,5 +68,6 @@ struct nfs_mount_data { | |||
| 68 | /* The following are for internal use only */ | 68 | /* The following are for internal use only */ |
| 69 | #define NFS_MOUNT_LOOKUP_CACHE_NONEG 0x10000 | 69 | #define NFS_MOUNT_LOOKUP_CACHE_NONEG 0x10000 |
| 70 | #define NFS_MOUNT_LOOKUP_CACHE_NONE 0x20000 | 70 | #define NFS_MOUNT_LOOKUP_CACHE_NONE 0x20000 |
| 71 | #define NFS_MOUNT_NORESVPORT 0x40000 | ||
| 71 | 72 | ||
| 72 | #endif | 73 | #endif |
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index c1c31acb8a2b..a550b528319f 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h | |||
| @@ -120,13 +120,14 @@ struct nfs_openargs { | |||
| 120 | const struct nfs_fh * fh; | 120 | const struct nfs_fh * fh; |
| 121 | struct nfs_seqid * seqid; | 121 | struct nfs_seqid * seqid; |
| 122 | int open_flags; | 122 | int open_flags; |
| 123 | fmode_t fmode; | ||
| 123 | __u64 clientid; | 124 | __u64 clientid; |
| 124 | __u64 id; | 125 | __u64 id; |
| 125 | union { | 126 | union { |
| 126 | struct iattr * attrs; /* UNCHECKED, GUARDED */ | 127 | struct iattr * attrs; /* UNCHECKED, GUARDED */ |
| 127 | nfs4_verifier verifier; /* EXCLUSIVE */ | 128 | nfs4_verifier verifier; /* EXCLUSIVE */ |
| 128 | nfs4_stateid delegation; /* CLAIM_DELEGATE_CUR */ | 129 | nfs4_stateid delegation; /* CLAIM_DELEGATE_CUR */ |
| 129 | int delegation_type; /* CLAIM_PREVIOUS */ | 130 | fmode_t delegation_type; /* CLAIM_PREVIOUS */ |
| 130 | } u; | 131 | } u; |
| 131 | const struct qstr * name; | 132 | const struct qstr * name; |
| 132 | const struct nfs_server *server; /* Needed for ID mapping */ | 133 | const struct nfs_server *server; /* Needed for ID mapping */ |
| @@ -143,7 +144,7 @@ struct nfs_openres { | |||
| 143 | struct nfs_fattr * dir_attr; | 144 | struct nfs_fattr * dir_attr; |
| 144 | struct nfs_seqid * seqid; | 145 | struct nfs_seqid * seqid; |
| 145 | const struct nfs_server *server; | 146 | const struct nfs_server *server; |
| 146 | int delegation_type; | 147 | fmode_t delegation_type; |
| 147 | nfs4_stateid delegation; | 148 | nfs4_stateid delegation; |
| 148 | __u32 do_recall; | 149 | __u32 do_recall; |
| 149 | __u64 maxsize; | 150 | __u64 maxsize; |
| @@ -171,7 +172,7 @@ struct nfs_closeargs { | |||
| 171 | struct nfs_fh * fh; | 172 | struct nfs_fh * fh; |
| 172 | nfs4_stateid * stateid; | 173 | nfs4_stateid * stateid; |
| 173 | struct nfs_seqid * seqid; | 174 | struct nfs_seqid * seqid; |
| 174 | int open_flags; | 175 | fmode_t fmode; |
| 175 | const u32 * bitmask; | 176 | const u32 * bitmask; |
| 176 | }; | 177 | }; |
| 177 | 178 | ||
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h index d0fe2e378452..128298c0362d 100644 --- a/include/linux/nfsd/state.h +++ b/include/linux/nfsd/state.h | |||
| @@ -124,6 +124,8 @@ struct nfs4_client { | |||
| 124 | nfs4_verifier cl_verifier; /* generated by client */ | 124 | nfs4_verifier cl_verifier; /* generated by client */ |
| 125 | time_t cl_time; /* time of last lease renewal */ | 125 | time_t cl_time; /* time of last lease renewal */ |
| 126 | __be32 cl_addr; /* client ipaddress */ | 126 | __be32 cl_addr; /* client ipaddress */ |
| 127 | u32 cl_flavor; /* setclientid pseudoflavor */ | ||
| 128 | char *cl_principal; /* setclientid principal name */ | ||
| 127 | struct svc_cred cl_cred; /* setclientid principal */ | 129 | struct svc_cred cl_cred; /* setclientid principal */ |
| 128 | clientid_t cl_clientid; /* generated by server */ | 130 | clientid_t cl_clientid; /* generated by server */ |
| 129 | nfs4_verifier cl_confirm; /* generated by server */ | 131 | nfs4_verifier cl_confirm; /* generated by server */ |
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 6f0ee1b84a4f..c39a21040dcb 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h | |||
| @@ -58,6 +58,7 @@ struct rpc_clnt { | |||
| 58 | struct rpc_timeout cl_timeout_default; | 58 | struct rpc_timeout cl_timeout_default; |
| 59 | struct rpc_program * cl_program; | 59 | struct rpc_program * cl_program; |
| 60 | char cl_inline_name[32]; | 60 | char cl_inline_name[32]; |
| 61 | char *cl_principal; /* target to authenticate to */ | ||
| 61 | }; | 62 | }; |
| 62 | 63 | ||
| 63 | /* | 64 | /* |
| @@ -108,6 +109,7 @@ struct rpc_create_args { | |||
| 108 | u32 version; | 109 | u32 version; |
| 109 | rpc_authflavor_t authflavor; | 110 | rpc_authflavor_t authflavor; |
| 110 | unsigned long flags; | 111 | unsigned long flags; |
| 112 | char *client_name; | ||
| 111 | }; | 113 | }; |
| 112 | 114 | ||
| 113 | /* Values for "flags" field */ | 115 | /* Values for "flags" field */ |
diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index 51b977a4ca20..cea764c2359f 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h | |||
| @@ -15,6 +15,7 @@ struct rpc_pipe_ops { | |||
| 15 | ssize_t (*upcall)(struct file *, struct rpc_pipe_msg *, char __user *, size_t); | 15 | ssize_t (*upcall)(struct file *, struct rpc_pipe_msg *, char __user *, size_t); |
| 16 | ssize_t (*downcall)(struct file *, const char __user *, size_t); | 16 | ssize_t (*downcall)(struct file *, const char __user *, size_t); |
| 17 | void (*release_pipe)(struct inode *); | 17 | void (*release_pipe)(struct inode *); |
| 18 | int (*open_pipe)(struct inode *); | ||
| 18 | void (*destroy_msg)(struct rpc_pipe_msg *); | 19 | void (*destroy_msg)(struct rpc_pipe_msg *); |
| 19 | }; | 20 | }; |
| 20 | 21 | ||
diff --git a/include/linux/sunrpc/svcauth_gss.h b/include/linux/sunrpc/svcauth_gss.h index c9165d9771a8..ca7d725861fc 100644 --- a/include/linux/sunrpc/svcauth_gss.h +++ b/include/linux/sunrpc/svcauth_gss.h | |||
| @@ -20,6 +20,7 @@ int gss_svc_init(void); | |||
| 20 | void gss_svc_shutdown(void); | 20 | void gss_svc_shutdown(void); |
| 21 | int svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name); | 21 | int svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name); |
| 22 | u32 svcauth_gss_flavor(struct auth_domain *dom); | 22 | u32 svcauth_gss_flavor(struct auth_domain *dom); |
| 23 | char *svc_gss_principal(struct svc_rqst *); | ||
| 23 | 24 | ||
| 24 | #endif /* __KERNEL__ */ | 25 | #endif /* __KERNEL__ */ |
| 25 | #endif /* _LINUX_SUNRPC_SVCAUTH_GSS_H */ | 26 | #endif /* _LINUX_SUNRPC_SVCAUTH_GSS_H */ |
diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index e4057d729f03..49e1eb454465 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h | |||
| @@ -37,21 +37,6 @@ struct xdr_netobj { | |||
| 37 | typedef int (*kxdrproc_t)(void *rqstp, __be32 *data, void *obj); | 37 | typedef int (*kxdrproc_t)(void *rqstp, __be32 *data, void *obj); |
| 38 | 38 | ||
| 39 | /* | 39 | /* |
| 40 | * We're still requiring the BKL in the xdr code until it's been | ||
| 41 | * more carefully audited, at which point this wrapper will become | ||
| 42 | * unnecessary. | ||
| 43 | */ | ||
| 44 | static inline int rpc_call_xdrproc(kxdrproc_t xdrproc, void *rqstp, __be32 *data, void *obj) | ||
| 45 | { | ||
| 46 | int ret; | ||
| 47 | |||
| 48 | lock_kernel(); | ||
| 49 | ret = xdrproc(rqstp, data, obj); | ||
| 50 | unlock_kernel(); | ||
| 51 | return ret; | ||
| 52 | } | ||
| 53 | |||
| 54 | /* | ||
| 55 | * Basic structure for transmission/reception of a client XDR message. | 40 | * Basic structure for transmission/reception of a client XDR message. |
| 56 | * Features a header (for a linear buffer containing RPC headers | 41 | * Features a header (for a linear buffer containing RPC headers |
| 57 | * and the data payload for short messages), and then an array of | 42 | * and the data payload for short messages), and then an array of |
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 4d80a118d538..11fc71d50c1e 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h | |||
| @@ -76,8 +76,7 @@ struct rpc_rqst { | |||
| 76 | struct list_head rq_list; | 76 | struct list_head rq_list; |
| 77 | 77 | ||
| 78 | __u32 * rq_buffer; /* XDR encode buffer */ | 78 | __u32 * rq_buffer; /* XDR encode buffer */ |
| 79 | size_t rq_bufsize, | 79 | size_t rq_callsize, |
| 80 | rq_callsize, | ||
| 81 | rq_rcvsize; | 80 | rq_rcvsize; |
| 82 | 81 | ||
| 83 | struct xdr_buf rq_private_buf; /* The receive buffer | 82 | struct xdr_buf rq_private_buf; /* The receive buffer |
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 0443f8349458..0c431c277af5 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c | |||
| @@ -234,7 +234,7 @@ rpcauth_prune_expired(struct list_head *free, int nr_to_scan) | |||
| 234 | list_for_each_entry_safe(cred, next, &cred_unused, cr_lru) { | 234 | list_for_each_entry_safe(cred, next, &cred_unused, cr_lru) { |
| 235 | 235 | ||
| 236 | /* Enforce a 60 second garbage collection moratorium */ | 236 | /* Enforce a 60 second garbage collection moratorium */ |
| 237 | if (time_in_range(cred->cr_expire, expired, jiffies) && | 237 | if (time_in_range_open(cred->cr_expire, expired, jiffies) && |
| 238 | test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) | 238 | test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) |
| 239 | continue; | 239 | continue; |
| 240 | 240 | ||
| @@ -515,7 +515,7 @@ rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, | |||
| 515 | if (cred->cr_ops->crwrap_req) | 515 | if (cred->cr_ops->crwrap_req) |
| 516 | return cred->cr_ops->crwrap_req(task, encode, rqstp, data, obj); | 516 | return cred->cr_ops->crwrap_req(task, encode, rqstp, data, obj); |
| 517 | /* By default, we encode the arguments normally. */ | 517 | /* By default, we encode the arguments normally. */ |
| 518 | return rpc_call_xdrproc(encode, rqstp, data, obj); | 518 | return encode(rqstp, data, obj); |
| 519 | } | 519 | } |
| 520 | 520 | ||
| 521 | int | 521 | int |
| @@ -530,7 +530,7 @@ rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, | |||
| 530 | return cred->cr_ops->crunwrap_resp(task, decode, rqstp, | 530 | return cred->cr_ops->crunwrap_resp(task, decode, rqstp, |
| 531 | data, obj); | 531 | data, obj); |
| 532 | /* By default, we decode the arguments normally. */ | 532 | /* By default, we decode the arguments normally. */ |
| 533 | return rpc_call_xdrproc(decode, rqstp, data, obj); | 533 | return decode(rqstp, data, obj); |
| 534 | } | 534 | } |
| 535 | 535 | ||
| 536 | int | 536 | int |
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 853a4142cea1..e630b38a6047 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
| @@ -72,11 +72,25 @@ struct gss_auth { | |||
| 72 | struct gss_api_mech *mech; | 72 | struct gss_api_mech *mech; |
| 73 | enum rpc_gss_svc service; | 73 | enum rpc_gss_svc service; |
| 74 | struct rpc_clnt *client; | 74 | struct rpc_clnt *client; |
| 75 | struct dentry *dentry; | 75 | /* |
| 76 | * There are two upcall pipes; dentry[1], named "gssd", is used | ||
| 77 | * for the new text-based upcall; dentry[0] is named after the | ||
| 78 | * mechanism (for example, "krb5") and exists for | ||
| 79 | * backwards-compatibility with older gssd's. | ||
| 80 | */ | ||
| 81 | struct dentry *dentry[2]; | ||
| 76 | }; | 82 | }; |
| 77 | 83 | ||
| 84 | /* pipe_version >= 0 if and only if someone has a pipe open. */ | ||
| 85 | static int pipe_version = -1; | ||
| 86 | static atomic_t pipe_users = ATOMIC_INIT(0); | ||
| 87 | static DEFINE_SPINLOCK(pipe_version_lock); | ||
| 88 | static struct rpc_wait_queue pipe_version_rpc_waitqueue; | ||
| 89 | static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue); | ||
| 90 | |||
| 78 | static void gss_free_ctx(struct gss_cl_ctx *); | 91 | static void gss_free_ctx(struct gss_cl_ctx *); |
| 79 | static struct rpc_pipe_ops gss_upcall_ops; | 92 | static struct rpc_pipe_ops gss_upcall_ops_v0; |
| 93 | static struct rpc_pipe_ops gss_upcall_ops_v1; | ||
| 80 | 94 | ||
| 81 | static inline struct gss_cl_ctx * | 95 | static inline struct gss_cl_ctx * |
| 82 | gss_get_ctx(struct gss_cl_ctx *ctx) | 96 | gss_get_ctx(struct gss_cl_ctx *ctx) |
| @@ -220,6 +234,7 @@ err: | |||
| 220 | return p; | 234 | return p; |
| 221 | } | 235 | } |
| 222 | 236 | ||
| 237 | #define UPCALL_BUF_LEN 128 | ||
| 223 | 238 | ||
| 224 | struct gss_upcall_msg { | 239 | struct gss_upcall_msg { |
| 225 | atomic_t count; | 240 | atomic_t count; |
| @@ -227,16 +242,41 @@ struct gss_upcall_msg { | |||
| 227 | struct rpc_pipe_msg msg; | 242 | struct rpc_pipe_msg msg; |
| 228 | struct list_head list; | 243 | struct list_head list; |
| 229 | struct gss_auth *auth; | 244 | struct gss_auth *auth; |
| 245 | struct rpc_inode *inode; | ||
| 230 | struct rpc_wait_queue rpc_waitqueue; | 246 | struct rpc_wait_queue rpc_waitqueue; |
| 231 | wait_queue_head_t waitqueue; | 247 | wait_queue_head_t waitqueue; |
| 232 | struct gss_cl_ctx *ctx; | 248 | struct gss_cl_ctx *ctx; |
| 249 | char databuf[UPCALL_BUF_LEN]; | ||
| 233 | }; | 250 | }; |
| 234 | 251 | ||
| 252 | static int get_pipe_version(void) | ||
| 253 | { | ||
| 254 | int ret; | ||
| 255 | |||
| 256 | spin_lock(&pipe_version_lock); | ||
| 257 | if (pipe_version >= 0) { | ||
| 258 | atomic_inc(&pipe_users); | ||
| 259 | ret = pipe_version; | ||
| 260 | } else | ||
| 261 | ret = -EAGAIN; | ||
| 262 | spin_unlock(&pipe_version_lock); | ||
| 263 | return ret; | ||
| 264 | } | ||
| 265 | |||
| 266 | static void put_pipe_version(void) | ||
| 267 | { | ||
| 268 | if (atomic_dec_and_lock(&pipe_users, &pipe_version_lock)) { | ||
| 269 | pipe_version = -1; | ||
| 270 | spin_unlock(&pipe_version_lock); | ||
| 271 | } | ||
| 272 | } | ||
| 273 | |||
| 235 | static void | 274 | static void |
| 236 | gss_release_msg(struct gss_upcall_msg *gss_msg) | 275 | gss_release_msg(struct gss_upcall_msg *gss_msg) |
| 237 | { | 276 | { |
| 238 | if (!atomic_dec_and_test(&gss_msg->count)) | 277 | if (!atomic_dec_and_test(&gss_msg->count)) |
| 239 | return; | 278 | return; |
| 279 | put_pipe_version(); | ||
| 240 | BUG_ON(!list_empty(&gss_msg->list)); | 280 | BUG_ON(!list_empty(&gss_msg->list)); |
| 241 | if (gss_msg->ctx != NULL) | 281 | if (gss_msg->ctx != NULL) |
| 242 | gss_put_ctx(gss_msg->ctx); | 282 | gss_put_ctx(gss_msg->ctx); |
| @@ -266,8 +306,8 @@ __gss_find_upcall(struct rpc_inode *rpci, uid_t uid) | |||
| 266 | static inline struct gss_upcall_msg * | 306 | static inline struct gss_upcall_msg * |
| 267 | gss_add_msg(struct gss_auth *gss_auth, struct gss_upcall_msg *gss_msg) | 307 | gss_add_msg(struct gss_auth *gss_auth, struct gss_upcall_msg *gss_msg) |
| 268 | { | 308 | { |
| 269 | struct inode *inode = gss_auth->dentry->d_inode; | 309 | struct rpc_inode *rpci = gss_msg->inode; |
| 270 | struct rpc_inode *rpci = RPC_I(inode); | 310 | struct inode *inode = &rpci->vfs_inode; |
| 271 | struct gss_upcall_msg *old; | 311 | struct gss_upcall_msg *old; |
| 272 | 312 | ||
| 273 | spin_lock(&inode->i_lock); | 313 | spin_lock(&inode->i_lock); |
| @@ -293,8 +333,7 @@ __gss_unhash_msg(struct gss_upcall_msg *gss_msg) | |||
| 293 | static void | 333 | static void |
| 294 | gss_unhash_msg(struct gss_upcall_msg *gss_msg) | 334 | gss_unhash_msg(struct gss_upcall_msg *gss_msg) |
| 295 | { | 335 | { |
| 296 | struct gss_auth *gss_auth = gss_msg->auth; | 336 | struct inode *inode = &gss_msg->inode->vfs_inode; |
| 297 | struct inode *inode = gss_auth->dentry->d_inode; | ||
| 298 | 337 | ||
| 299 | if (list_empty(&gss_msg->list)) | 338 | if (list_empty(&gss_msg->list)) |
| 300 | return; | 339 | return; |
| @@ -310,7 +349,7 @@ gss_upcall_callback(struct rpc_task *task) | |||
| 310 | struct gss_cred *gss_cred = container_of(task->tk_msg.rpc_cred, | 349 | struct gss_cred *gss_cred = container_of(task->tk_msg.rpc_cred, |
| 311 | struct gss_cred, gc_base); | 350 | struct gss_cred, gc_base); |
| 312 | struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall; | 351 | struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall; |
| 313 | struct inode *inode = gss_msg->auth->dentry->d_inode; | 352 | struct inode *inode = &gss_msg->inode->vfs_inode; |
| 314 | 353 | ||
| 315 | spin_lock(&inode->i_lock); | 354 | spin_lock(&inode->i_lock); |
| 316 | if (gss_msg->ctx) | 355 | if (gss_msg->ctx) |
| @@ -323,22 +362,75 @@ gss_upcall_callback(struct rpc_task *task) | |||
| 323 | gss_release_msg(gss_msg); | 362 | gss_release_msg(gss_msg); |
| 324 | } | 363 | } |
| 325 | 364 | ||
| 365 | static void gss_encode_v0_msg(struct gss_upcall_msg *gss_msg) | ||
| 366 | { | ||
| 367 | gss_msg->msg.data = &gss_msg->uid; | ||
| 368 | gss_msg->msg.len = sizeof(gss_msg->uid); | ||
| 369 | } | ||
| 370 | |||
| 371 | static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg, | ||
| 372 | struct rpc_clnt *clnt, int machine_cred) | ||
| 373 | { | ||
| 374 | char *p = gss_msg->databuf; | ||
| 375 | int len = 0; | ||
| 376 | |||
| 377 | gss_msg->msg.len = sprintf(gss_msg->databuf, "mech=%s uid=%d ", | ||
| 378 | gss_msg->auth->mech->gm_name, | ||
| 379 | gss_msg->uid); | ||
| 380 | p += gss_msg->msg.len; | ||
| 381 | if (clnt->cl_principal) { | ||
| 382 | len = sprintf(p, "target=%s ", clnt->cl_principal); | ||
| 383 | p += len; | ||
| 384 | gss_msg->msg.len += len; | ||
| 385 | } | ||
| 386 | if (machine_cred) { | ||
| 387 | len = sprintf(p, "service=* "); | ||
| 388 | p += len; | ||
| 389 | gss_msg->msg.len += len; | ||
| 390 | } else if (!strcmp(clnt->cl_program->name, "nfs4_cb")) { | ||
| 391 | len = sprintf(p, "service=nfs "); | ||
| 392 | p += len; | ||
| 393 | gss_msg->msg.len += len; | ||
| 394 | } | ||
| 395 | len = sprintf(p, "\n"); | ||
| 396 | gss_msg->msg.len += len; | ||
| 397 | |||
| 398 | gss_msg->msg.data = gss_msg->databuf; | ||
| 399 | BUG_ON(gss_msg->msg.len > UPCALL_BUF_LEN); | ||
| 400 | } | ||
| 401 | |||
| 402 | static void gss_encode_msg(struct gss_upcall_msg *gss_msg, | ||
| 403 | struct rpc_clnt *clnt, int machine_cred) | ||
| 404 | { | ||
| 405 | if (pipe_version == 0) | ||
| 406 | gss_encode_v0_msg(gss_msg); | ||
| 407 | else /* pipe_version == 1 */ | ||
| 408 | gss_encode_v1_msg(gss_msg, clnt, machine_cred); | ||
| 409 | } | ||
| 410 | |||
| 326 | static inline struct gss_upcall_msg * | 411 | static inline struct gss_upcall_msg * |
| 327 | gss_alloc_msg(struct gss_auth *gss_auth, uid_t uid) | 412 | gss_alloc_msg(struct gss_auth *gss_auth, uid_t uid, struct rpc_clnt *clnt, |
| 413 | int machine_cred) | ||
| 328 | { | 414 | { |
| 329 | struct gss_upcall_msg *gss_msg; | 415 | struct gss_upcall_msg *gss_msg; |
| 416 | int vers; | ||
| 330 | 417 | ||
| 331 | gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS); | 418 | gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS); |
| 332 | if (gss_msg != NULL) { | 419 | if (gss_msg == NULL) |
| 333 | INIT_LIST_HEAD(&gss_msg->list); | 420 | return ERR_PTR(-ENOMEM); |
| 334 | rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq"); | 421 | vers = get_pipe_version(); |
| 335 | init_waitqueue_head(&gss_msg->waitqueue); | 422 | if (vers < 0) { |
| 336 | atomic_set(&gss_msg->count, 1); | 423 | kfree(gss_msg); |
| 337 | gss_msg->msg.data = &gss_msg->uid; | 424 | return ERR_PTR(vers); |
| 338 | gss_msg->msg.len = sizeof(gss_msg->uid); | ||
| 339 | gss_msg->uid = uid; | ||
| 340 | gss_msg->auth = gss_auth; | ||
| 341 | } | 425 | } |
| 426 | gss_msg->inode = RPC_I(gss_auth->dentry[vers]->d_inode); | ||
| 427 | INIT_LIST_HEAD(&gss_msg->list); | ||
| 428 | rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq"); | ||
| 429 | init_waitqueue_head(&gss_msg->waitqueue); | ||
| 430 | atomic_set(&gss_msg->count, 1); | ||
| 431 | gss_msg->uid = uid; | ||
| 432 | gss_msg->auth = gss_auth; | ||
| 433 | gss_encode_msg(gss_msg, clnt, machine_cred); | ||
| 342 | return gss_msg; | 434 | return gss_msg; |
| 343 | } | 435 | } |
| 344 | 436 | ||
| @@ -350,16 +442,13 @@ gss_setup_upcall(struct rpc_clnt *clnt, struct gss_auth *gss_auth, struct rpc_cr | |||
| 350 | struct gss_upcall_msg *gss_new, *gss_msg; | 442 | struct gss_upcall_msg *gss_new, *gss_msg; |
| 351 | uid_t uid = cred->cr_uid; | 443 | uid_t uid = cred->cr_uid; |
| 352 | 444 | ||
| 353 | /* Special case: rpc.gssd assumes that uid == 0 implies machine creds */ | 445 | gss_new = gss_alloc_msg(gss_auth, uid, clnt, gss_cred->gc_machine_cred); |
| 354 | if (gss_cred->gc_machine_cred != 0) | 446 | if (IS_ERR(gss_new)) |
| 355 | uid = 0; | 447 | return gss_new; |
| 356 | |||
| 357 | gss_new = gss_alloc_msg(gss_auth, uid); | ||
| 358 | if (gss_new == NULL) | ||
| 359 | return ERR_PTR(-ENOMEM); | ||
| 360 | gss_msg = gss_add_msg(gss_auth, gss_new); | 448 | gss_msg = gss_add_msg(gss_auth, gss_new); |
| 361 | if (gss_msg == gss_new) { | 449 | if (gss_msg == gss_new) { |
| 362 | int res = rpc_queue_upcall(gss_auth->dentry->d_inode, &gss_new->msg); | 450 | struct inode *inode = &gss_new->inode->vfs_inode; |
| 451 | int res = rpc_queue_upcall(inode, &gss_new->msg); | ||
| 363 | if (res) { | 452 | if (res) { |
| 364 | gss_unhash_msg(gss_new); | 453 | gss_unhash_msg(gss_new); |
| 365 | gss_msg = ERR_PTR(res); | 454 | gss_msg = ERR_PTR(res); |
| @@ -369,6 +458,18 @@ gss_setup_upcall(struct rpc_clnt *clnt, struct gss_auth *gss_auth, struct rpc_cr | |||
| 369 | return gss_msg; | 458 | return gss_msg; |
| 370 | } | 459 | } |
| 371 | 460 | ||
| 461 | static void warn_gssd(void) | ||
| 462 | { | ||
| 463 | static unsigned long ratelimit; | ||
| 464 | unsigned long now = jiffies; | ||
| 465 | |||
| 466 | if (time_after(now, ratelimit)) { | ||
| 467 | printk(KERN_WARNING "RPC: AUTH_GSS upcall timed out.\n" | ||
| 468 | "Please check user daemon is running.\n"); | ||
| 469 | ratelimit = now + 15*HZ; | ||
| 470 | } | ||
| 471 | } | ||
| 472 | |||
| 372 | static inline int | 473 | static inline int |
| 373 | gss_refresh_upcall(struct rpc_task *task) | 474 | gss_refresh_upcall(struct rpc_task *task) |
| 374 | { | 475 | { |
| @@ -378,16 +479,25 @@ gss_refresh_upcall(struct rpc_task *task) | |||
| 378 | struct gss_cred *gss_cred = container_of(cred, | 479 | struct gss_cred *gss_cred = container_of(cred, |
| 379 | struct gss_cred, gc_base); | 480 | struct gss_cred, gc_base); |
| 380 | struct gss_upcall_msg *gss_msg; | 481 | struct gss_upcall_msg *gss_msg; |
| 381 | struct inode *inode = gss_auth->dentry->d_inode; | 482 | struct inode *inode; |
| 382 | int err = 0; | 483 | int err = 0; |
| 383 | 484 | ||
| 384 | dprintk("RPC: %5u gss_refresh_upcall for uid %u\n", task->tk_pid, | 485 | dprintk("RPC: %5u gss_refresh_upcall for uid %u\n", task->tk_pid, |
| 385 | cred->cr_uid); | 486 | cred->cr_uid); |
| 386 | gss_msg = gss_setup_upcall(task->tk_client, gss_auth, cred); | 487 | gss_msg = gss_setup_upcall(task->tk_client, gss_auth, cred); |
| 488 | if (IS_ERR(gss_msg) == -EAGAIN) { | ||
| 489 | /* XXX: warning on the first, under the assumption we | ||
| 490 | * shouldn't normally hit this case on a refresh. */ | ||
| 491 | warn_gssd(); | ||
| 492 | task->tk_timeout = 15*HZ; | ||
| 493 | rpc_sleep_on(&pipe_version_rpc_waitqueue, task, NULL); | ||
| 494 | return 0; | ||
| 495 | } | ||
| 387 | if (IS_ERR(gss_msg)) { | 496 | if (IS_ERR(gss_msg)) { |
| 388 | err = PTR_ERR(gss_msg); | 497 | err = PTR_ERR(gss_msg); |
| 389 | goto out; | 498 | goto out; |
| 390 | } | 499 | } |
| 500 | inode = &gss_msg->inode->vfs_inode; | ||
| 391 | spin_lock(&inode->i_lock); | 501 | spin_lock(&inode->i_lock); |
| 392 | if (gss_cred->gc_upcall != NULL) | 502 | if (gss_cred->gc_upcall != NULL) |
| 393 | rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL); | 503 | rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL); |
| @@ -414,18 +524,29 @@ out: | |||
| 414 | static inline int | 524 | static inline int |
| 415 | gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) | 525 | gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) |
| 416 | { | 526 | { |
| 417 | struct inode *inode = gss_auth->dentry->d_inode; | 527 | struct inode *inode; |
| 418 | struct rpc_cred *cred = &gss_cred->gc_base; | 528 | struct rpc_cred *cred = &gss_cred->gc_base; |
| 419 | struct gss_upcall_msg *gss_msg; | 529 | struct gss_upcall_msg *gss_msg; |
| 420 | DEFINE_WAIT(wait); | 530 | DEFINE_WAIT(wait); |
| 421 | int err = 0; | 531 | int err = 0; |
| 422 | 532 | ||
| 423 | dprintk("RPC: gss_upcall for uid %u\n", cred->cr_uid); | 533 | dprintk("RPC: gss_upcall for uid %u\n", cred->cr_uid); |
| 534 | retry: | ||
| 424 | gss_msg = gss_setup_upcall(gss_auth->client, gss_auth, cred); | 535 | gss_msg = gss_setup_upcall(gss_auth->client, gss_auth, cred); |
| 536 | if (PTR_ERR(gss_msg) == -EAGAIN) { | ||
| 537 | err = wait_event_interruptible_timeout(pipe_version_waitqueue, | ||
| 538 | pipe_version >= 0, 15*HZ); | ||
| 539 | if (err) | ||
| 540 | goto out; | ||
| 541 | if (pipe_version < 0) | ||
| 542 | warn_gssd(); | ||
| 543 | goto retry; | ||
| 544 | } | ||
| 425 | if (IS_ERR(gss_msg)) { | 545 | if (IS_ERR(gss_msg)) { |
| 426 | err = PTR_ERR(gss_msg); | 546 | err = PTR_ERR(gss_msg); |
| 427 | goto out; | 547 | goto out; |
| 428 | } | 548 | } |
| 549 | inode = &gss_msg->inode->vfs_inode; | ||
| 429 | for (;;) { | 550 | for (;;) { |
| 430 | prepare_to_wait(&gss_msg->waitqueue, &wait, TASK_INTERRUPTIBLE); | 551 | prepare_to_wait(&gss_msg->waitqueue, &wait, TASK_INTERRUPTIBLE); |
| 431 | spin_lock(&inode->i_lock); | 552 | spin_lock(&inode->i_lock); |
| @@ -543,6 +664,38 @@ out: | |||
| 543 | return err; | 664 | return err; |
| 544 | } | 665 | } |
| 545 | 666 | ||
| 667 | static int gss_pipe_open(struct inode *inode, int new_version) | ||
| 668 | { | ||
| 669 | int ret = 0; | ||
| 670 | |||
| 671 | spin_lock(&pipe_version_lock); | ||
| 672 | if (pipe_version < 0) { | ||
| 673 | /* First open of any gss pipe determines the version: */ | ||
| 674 | pipe_version = new_version; | ||
| 675 | rpc_wake_up(&pipe_version_rpc_waitqueue); | ||
| 676 | wake_up(&pipe_version_waitqueue); | ||
| 677 | } else if (pipe_version != new_version) { | ||
| 678 | /* Trying to open a pipe of a different version */ | ||
| 679 | ret = -EBUSY; | ||
| 680 | goto out; | ||
| 681 | } | ||
| 682 | atomic_inc(&pipe_users); | ||
| 683 | out: | ||
| 684 | spin_unlock(&pipe_version_lock); | ||
| 685 | return ret; | ||
| 686 | |||
| 687 | } | ||
| 688 | |||
| 689 | static int gss_pipe_open_v0(struct inode *inode) | ||
| 690 | { | ||
| 691 | return gss_pipe_open(inode, 0); | ||
| 692 | } | ||
| 693 | |||
| 694 | static int gss_pipe_open_v1(struct inode *inode) | ||
| 695 | { | ||
| 696 | return gss_pipe_open(inode, 1); | ||
| 697 | } | ||
| 698 | |||
| 546 | static void | 699 | static void |
| 547 | gss_pipe_release(struct inode *inode) | 700 | gss_pipe_release(struct inode *inode) |
| 548 | { | 701 | { |
| @@ -562,27 +715,22 @@ gss_pipe_release(struct inode *inode) | |||
| 562 | spin_lock(&inode->i_lock); | 715 | spin_lock(&inode->i_lock); |
| 563 | } | 716 | } |
| 564 | spin_unlock(&inode->i_lock); | 717 | spin_unlock(&inode->i_lock); |
| 718 | |||
| 719 | put_pipe_version(); | ||
| 565 | } | 720 | } |
| 566 | 721 | ||
| 567 | static void | 722 | static void |
| 568 | gss_pipe_destroy_msg(struct rpc_pipe_msg *msg) | 723 | gss_pipe_destroy_msg(struct rpc_pipe_msg *msg) |
| 569 | { | 724 | { |
| 570 | struct gss_upcall_msg *gss_msg = container_of(msg, struct gss_upcall_msg, msg); | 725 | struct gss_upcall_msg *gss_msg = container_of(msg, struct gss_upcall_msg, msg); |
| 571 | static unsigned long ratelimit; | ||
| 572 | 726 | ||
| 573 | if (msg->errno < 0) { | 727 | if (msg->errno < 0) { |
| 574 | dprintk("RPC: gss_pipe_destroy_msg releasing msg %p\n", | 728 | dprintk("RPC: gss_pipe_destroy_msg releasing msg %p\n", |
| 575 | gss_msg); | 729 | gss_msg); |
| 576 | atomic_inc(&gss_msg->count); | 730 | atomic_inc(&gss_msg->count); |
| 577 | gss_unhash_msg(gss_msg); | 731 | gss_unhash_msg(gss_msg); |
| 578 | if (msg->errno == -ETIMEDOUT) { | 732 | if (msg->errno == -ETIMEDOUT) |
| 579 | unsigned long now = jiffies; | 733 | warn_gssd(); |
| 580 | if (time_after(now, ratelimit)) { | ||
| 581 | printk(KERN_WARNING "RPC: AUTH_GSS upcall timed out.\n" | ||
| 582 | "Please check user daemon is running!\n"); | ||
| 583 | ratelimit = now + 15*HZ; | ||
| 584 | } | ||
| 585 | } | ||
| 586 | gss_release_msg(gss_msg); | 734 | gss_release_msg(gss_msg); |
| 587 | } | 735 | } |
| 588 | } | 736 | } |
| @@ -623,20 +771,38 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) | |||
| 623 | atomic_set(&auth->au_count, 1); | 771 | atomic_set(&auth->au_count, 1); |
| 624 | kref_init(&gss_auth->kref); | 772 | kref_init(&gss_auth->kref); |
| 625 | 773 | ||
| 626 | gss_auth->dentry = rpc_mkpipe(clnt->cl_dentry, gss_auth->mech->gm_name, | 774 | /* |
| 627 | clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN); | 775 | * Note: if we created the old pipe first, then someone who |
| 628 | if (IS_ERR(gss_auth->dentry)) { | 776 | * examined the directory at the right moment might conclude |
| 629 | err = PTR_ERR(gss_auth->dentry); | 777 | * that we supported only the old pipe. So we instead create |
| 778 | * the new pipe first. | ||
| 779 | */ | ||
| 780 | gss_auth->dentry[1] = rpc_mkpipe(clnt->cl_dentry, | ||
| 781 | "gssd", | ||
| 782 | clnt, &gss_upcall_ops_v1, | ||
| 783 | RPC_PIPE_WAIT_FOR_OPEN); | ||
| 784 | if (IS_ERR(gss_auth->dentry[1])) { | ||
| 785 | err = PTR_ERR(gss_auth->dentry[1]); | ||
| 630 | goto err_put_mech; | 786 | goto err_put_mech; |
| 631 | } | 787 | } |
| 632 | 788 | ||
| 789 | gss_auth->dentry[0] = rpc_mkpipe(clnt->cl_dentry, | ||
| 790 | gss_auth->mech->gm_name, | ||
| 791 | clnt, &gss_upcall_ops_v0, | ||
| 792 | RPC_PIPE_WAIT_FOR_OPEN); | ||
| 793 | if (IS_ERR(gss_auth->dentry[0])) { | ||
| 794 | err = PTR_ERR(gss_auth->dentry[0]); | ||
| 795 | goto err_unlink_pipe_1; | ||
| 796 | } | ||
| 633 | err = rpcauth_init_credcache(auth); | 797 | err = rpcauth_init_credcache(auth); |
| 634 | if (err) | 798 | if (err) |
| 635 | goto err_unlink_pipe; | 799 | goto err_unlink_pipe_0; |
| 636 | 800 | ||
| 637 | return auth; | 801 | return auth; |
| 638 | err_unlink_pipe: | 802 | err_unlink_pipe_0: |
| 639 | rpc_unlink(gss_auth->dentry); | 803 | rpc_unlink(gss_auth->dentry[0]); |
| 804 | err_unlink_pipe_1: | ||
| 805 | rpc_unlink(gss_auth->dentry[1]); | ||
| 640 | err_put_mech: | 806 | err_put_mech: |
| 641 | gss_mech_put(gss_auth->mech); | 807 | gss_mech_put(gss_auth->mech); |
| 642 | err_free: | 808 | err_free: |
| @@ -649,8 +815,8 @@ out_dec: | |||
| 649 | static void | 815 | static void |
| 650 | gss_free(struct gss_auth *gss_auth) | 816 | gss_free(struct gss_auth *gss_auth) |
| 651 | { | 817 | { |
| 652 | rpc_unlink(gss_auth->dentry); | 818 | rpc_unlink(gss_auth->dentry[1]); |
| 653 | gss_auth->dentry = NULL; | 819 | rpc_unlink(gss_auth->dentry[0]); |
| 654 | gss_mech_put(gss_auth->mech); | 820 | gss_mech_put(gss_auth->mech); |
| 655 | 821 | ||
| 656 | kfree(gss_auth); | 822 | kfree(gss_auth); |
| @@ -693,7 +859,7 @@ gss_destroying_context(struct rpc_cred *cred) | |||
| 693 | struct rpc_task *task; | 859 | struct rpc_task *task; |
| 694 | 860 | ||
| 695 | if (gss_cred->gc_ctx == NULL || | 861 | if (gss_cred->gc_ctx == NULL || |
| 696 | test_and_clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0) | 862 | test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0) |
| 697 | return 0; | 863 | return 0; |
| 698 | 864 | ||
| 699 | gss_cred->gc_ctx->gc_proc = RPC_GSS_PROC_DESTROY; | 865 | gss_cred->gc_ctx->gc_proc = RPC_GSS_PROC_DESTROY; |
| @@ -757,14 +923,12 @@ gss_free_cred_callback(struct rcu_head *head) | |||
| 757 | } | 923 | } |
| 758 | 924 | ||
| 759 | static void | 925 | static void |
| 760 | gss_destroy_cred(struct rpc_cred *cred) | 926 | gss_destroy_nullcred(struct rpc_cred *cred) |
| 761 | { | 927 | { |
| 762 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); | 928 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); |
| 763 | struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth); | 929 | struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth); |
| 764 | struct gss_cl_ctx *ctx = gss_cred->gc_ctx; | 930 | struct gss_cl_ctx *ctx = gss_cred->gc_ctx; |
| 765 | 931 | ||
| 766 | if (gss_destroying_context(cred)) | ||
| 767 | return; | ||
| 768 | rcu_assign_pointer(gss_cred->gc_ctx, NULL); | 932 | rcu_assign_pointer(gss_cred->gc_ctx, NULL); |
| 769 | call_rcu(&cred->cr_rcu, gss_free_cred_callback); | 933 | call_rcu(&cred->cr_rcu, gss_free_cred_callback); |
| 770 | if (ctx) | 934 | if (ctx) |
| @@ -772,6 +936,15 @@ gss_destroy_cred(struct rpc_cred *cred) | |||
| 772 | kref_put(&gss_auth->kref, gss_free_callback); | 936 | kref_put(&gss_auth->kref, gss_free_callback); |
| 773 | } | 937 | } |
| 774 | 938 | ||
| 939 | static void | ||
| 940 | gss_destroy_cred(struct rpc_cred *cred) | ||
| 941 | { | ||
| 942 | |||
| 943 | if (gss_destroying_context(cred)) | ||
| 944 | return; | ||
| 945 | gss_destroy_nullcred(cred); | ||
| 946 | } | ||
| 947 | |||
| 775 | /* | 948 | /* |
| 776 | * Lookup RPCSEC_GSS cred for the current process | 949 | * Lookup RPCSEC_GSS cred for the current process |
| 777 | */ | 950 | */ |
| @@ -1017,7 +1190,7 @@ gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx, | |||
| 1017 | offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base; | 1190 | offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base; |
| 1018 | *p++ = htonl(rqstp->rq_seqno); | 1191 | *p++ = htonl(rqstp->rq_seqno); |
| 1019 | 1192 | ||
| 1020 | status = rpc_call_xdrproc(encode, rqstp, p, obj); | 1193 | status = encode(rqstp, p, obj); |
| 1021 | if (status) | 1194 | if (status) |
| 1022 | return status; | 1195 | return status; |
| 1023 | 1196 | ||
| @@ -1111,7 +1284,7 @@ gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx, | |||
| 1111 | offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base; | 1284 | offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base; |
| 1112 | *p++ = htonl(rqstp->rq_seqno); | 1285 | *p++ = htonl(rqstp->rq_seqno); |
| 1113 | 1286 | ||
| 1114 | status = rpc_call_xdrproc(encode, rqstp, p, obj); | 1287 | status = encode(rqstp, p, obj); |
| 1115 | if (status) | 1288 | if (status) |
| 1116 | return status; | 1289 | return status; |
| 1117 | 1290 | ||
| @@ -1170,12 +1343,12 @@ gss_wrap_req(struct rpc_task *task, | |||
| 1170 | /* The spec seems a little ambiguous here, but I think that not | 1343 | /* The spec seems a little ambiguous here, but I think that not |
| 1171 | * wrapping context destruction requests makes the most sense. | 1344 | * wrapping context destruction requests makes the most sense. |
| 1172 | */ | 1345 | */ |
| 1173 | status = rpc_call_xdrproc(encode, rqstp, p, obj); | 1346 | status = encode(rqstp, p, obj); |
| 1174 | goto out; | 1347 | goto out; |
| 1175 | } | 1348 | } |
| 1176 | switch (gss_cred->gc_service) { | 1349 | switch (gss_cred->gc_service) { |
| 1177 | case RPC_GSS_SVC_NONE: | 1350 | case RPC_GSS_SVC_NONE: |
| 1178 | status = rpc_call_xdrproc(encode, rqstp, p, obj); | 1351 | status = encode(rqstp, p, obj); |
| 1179 | break; | 1352 | break; |
| 1180 | case RPC_GSS_SVC_INTEGRITY: | 1353 | case RPC_GSS_SVC_INTEGRITY: |
| 1181 | status = gss_wrap_req_integ(cred, ctx, encode, | 1354 | status = gss_wrap_req_integ(cred, ctx, encode, |
| @@ -1291,7 +1464,7 @@ gss_unwrap_resp(struct rpc_task *task, | |||
| 1291 | cred->cr_auth->au_rslack = cred->cr_auth->au_verfsize + (p - savedp) | 1464 | cred->cr_auth->au_rslack = cred->cr_auth->au_verfsize + (p - savedp) |
| 1292 | + (savedlen - head->iov_len); | 1465 | + (savedlen - head->iov_len); |
| 1293 | out_decode: | 1466 | out_decode: |
| 1294 | status = rpc_call_xdrproc(decode, rqstp, p, obj); | 1467 | status = decode(rqstp, p, obj); |
| 1295 | out: | 1468 | out: |
| 1296 | gss_put_ctx(ctx); | 1469 | gss_put_ctx(ctx); |
| 1297 | dprintk("RPC: %5u gss_unwrap_resp returning %d\n", task->tk_pid, | 1470 | dprintk("RPC: %5u gss_unwrap_resp returning %d\n", task->tk_pid, |
| @@ -1324,7 +1497,7 @@ static const struct rpc_credops gss_credops = { | |||
| 1324 | 1497 | ||
| 1325 | static const struct rpc_credops gss_nullops = { | 1498 | static const struct rpc_credops gss_nullops = { |
| 1326 | .cr_name = "AUTH_GSS", | 1499 | .cr_name = "AUTH_GSS", |
| 1327 | .crdestroy = gss_destroy_cred, | 1500 | .crdestroy = gss_destroy_nullcred, |
| 1328 | .crbind = rpcauth_generic_bind_cred, | 1501 | .crbind = rpcauth_generic_bind_cred, |
| 1329 | .crmatch = gss_match, | 1502 | .crmatch = gss_match, |
| 1330 | .crmarshal = gss_marshal, | 1503 | .crmarshal = gss_marshal, |
| @@ -1334,10 +1507,19 @@ static const struct rpc_credops gss_nullops = { | |||
| 1334 | .crunwrap_resp = gss_unwrap_resp, | 1507 | .crunwrap_resp = gss_unwrap_resp, |
| 1335 | }; | 1508 | }; |
| 1336 | 1509 | ||
| 1337 | static struct rpc_pipe_ops gss_upcall_ops = { | 1510 | static struct rpc_pipe_ops gss_upcall_ops_v0 = { |
| 1511 | .upcall = gss_pipe_upcall, | ||
| 1512 | .downcall = gss_pipe_downcall, | ||
| 1513 | .destroy_msg = gss_pipe_destroy_msg, | ||
| 1514 | .open_pipe = gss_pipe_open_v0, | ||
| 1515 | .release_pipe = gss_pipe_release, | ||
| 1516 | }; | ||
| 1517 | |||
| 1518 | static struct rpc_pipe_ops gss_upcall_ops_v1 = { | ||
| 1338 | .upcall = gss_pipe_upcall, | 1519 | .upcall = gss_pipe_upcall, |
| 1339 | .downcall = gss_pipe_downcall, | 1520 | .downcall = gss_pipe_downcall, |
| 1340 | .destroy_msg = gss_pipe_destroy_msg, | 1521 | .destroy_msg = gss_pipe_destroy_msg, |
| 1522 | .open_pipe = gss_pipe_open_v1, | ||
| 1341 | .release_pipe = gss_pipe_release, | 1523 | .release_pipe = gss_pipe_release, |
| 1342 | }; | 1524 | }; |
| 1343 | 1525 | ||
| @@ -1354,6 +1536,7 @@ static int __init init_rpcsec_gss(void) | |||
| 1354 | err = gss_svc_init(); | 1536 | err = gss_svc_init(); |
| 1355 | if (err) | 1537 | if (err) |
| 1356 | goto out_unregister; | 1538 | goto out_unregister; |
| 1539 | rpc_init_wait_queue(&pipe_version_rpc_waitqueue, "gss pipe version"); | ||
| 1357 | return 0; | 1540 | return 0; |
| 1358 | out_unregister: | 1541 | out_unregister: |
| 1359 | rpcauth_unregister(&authgss_ops); | 1542 | rpcauth_unregister(&authgss_ops); |
diff --git a/net/sunrpc/auth_gss/gss_generic_token.c b/net/sunrpc/auth_gss/gss_generic_token.c index d83b881685fe..c0ba39c4f5f2 100644 --- a/net/sunrpc/auth_gss/gss_generic_token.c +++ b/net/sunrpc/auth_gss/gss_generic_token.c | |||
| @@ -152,7 +152,7 @@ g_token_size(struct xdr_netobj *mech, unsigned int body_size) | |||
| 152 | return(1 + der_length_size(body_size) + body_size); | 152 | return(1 + der_length_size(body_size) + body_size); |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | EXPORT_SYMBOL(g_token_size); | 155 | EXPORT_SYMBOL_GPL(g_token_size); |
| 156 | 156 | ||
| 157 | /* fills in a buffer with the token header. The buffer is assumed to | 157 | /* fills in a buffer with the token header. The buffer is assumed to |
| 158 | be the right size. buf is advanced past the token header */ | 158 | be the right size. buf is advanced past the token header */ |
| @@ -167,7 +167,7 @@ g_make_token_header(struct xdr_netobj *mech, int body_size, unsigned char **buf) | |||
| 167 | TWRITE_STR(*buf, mech->data, ((int) mech->len)); | 167 | TWRITE_STR(*buf, mech->data, ((int) mech->len)); |
| 168 | } | 168 | } |
| 169 | 169 | ||
| 170 | EXPORT_SYMBOL(g_make_token_header); | 170 | EXPORT_SYMBOL_GPL(g_make_token_header); |
| 171 | 171 | ||
| 172 | /* | 172 | /* |
| 173 | * Given a buffer containing a token, reads and verifies the token, | 173 | * Given a buffer containing a token, reads and verifies the token, |
| @@ -231,5 +231,5 @@ g_verify_token_header(struct xdr_netobj *mech, int *body_size, | |||
| 231 | return(ret); | 231 | return(ret); |
| 232 | } | 232 | } |
| 233 | 233 | ||
| 234 | EXPORT_SYMBOL(g_verify_token_header); | 234 | EXPORT_SYMBOL_GPL(g_verify_token_header); |
| 235 | 235 | ||
diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c index bce9d527af08..6efbb0cd3c7c 100644 --- a/net/sunrpc/auth_gss/gss_mech_switch.c +++ b/net/sunrpc/auth_gss/gss_mech_switch.c | |||
| @@ -117,7 +117,7 @@ gss_mech_register(struct gss_api_mech *gm) | |||
| 117 | return 0; | 117 | return 0; |
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | EXPORT_SYMBOL(gss_mech_register); | 120 | EXPORT_SYMBOL_GPL(gss_mech_register); |
| 121 | 121 | ||
| 122 | void | 122 | void |
| 123 | gss_mech_unregister(struct gss_api_mech *gm) | 123 | gss_mech_unregister(struct gss_api_mech *gm) |
| @@ -129,7 +129,7 @@ gss_mech_unregister(struct gss_api_mech *gm) | |||
| 129 | gss_mech_free(gm); | 129 | gss_mech_free(gm); |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | EXPORT_SYMBOL(gss_mech_unregister); | 132 | EXPORT_SYMBOL_GPL(gss_mech_unregister); |
| 133 | 133 | ||
| 134 | struct gss_api_mech * | 134 | struct gss_api_mech * |
| 135 | gss_mech_get(struct gss_api_mech *gm) | 135 | gss_mech_get(struct gss_api_mech *gm) |
| @@ -138,7 +138,7 @@ gss_mech_get(struct gss_api_mech *gm) | |||
| 138 | return gm; | 138 | return gm; |
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | EXPORT_SYMBOL(gss_mech_get); | 141 | EXPORT_SYMBOL_GPL(gss_mech_get); |
| 142 | 142 | ||
| 143 | struct gss_api_mech * | 143 | struct gss_api_mech * |
| 144 | gss_mech_get_by_name(const char *name) | 144 | gss_mech_get_by_name(const char *name) |
| @@ -158,7 +158,7 @@ gss_mech_get_by_name(const char *name) | |||
| 158 | 158 | ||
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | EXPORT_SYMBOL(gss_mech_get_by_name); | 161 | EXPORT_SYMBOL_GPL(gss_mech_get_by_name); |
| 162 | 162 | ||
| 163 | static inline int | 163 | static inline int |
| 164 | mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor) | 164 | mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor) |
| @@ -191,7 +191,7 @@ gss_mech_get_by_pseudoflavor(u32 pseudoflavor) | |||
| 191 | return gm; | 191 | return gm; |
| 192 | } | 192 | } |
| 193 | 193 | ||
| 194 | EXPORT_SYMBOL(gss_mech_get_by_pseudoflavor); | 194 | EXPORT_SYMBOL_GPL(gss_mech_get_by_pseudoflavor); |
| 195 | 195 | ||
| 196 | u32 | 196 | u32 |
| 197 | gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 service) | 197 | gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 service) |
| @@ -205,7 +205,7 @@ gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 service) | |||
| 205 | } | 205 | } |
| 206 | return RPC_AUTH_MAXFLAVOR; /* illegal value */ | 206 | return RPC_AUTH_MAXFLAVOR; /* illegal value */ |
| 207 | } | 207 | } |
| 208 | EXPORT_SYMBOL(gss_svc_to_pseudoflavor); | 208 | EXPORT_SYMBOL_GPL(gss_svc_to_pseudoflavor); |
| 209 | 209 | ||
| 210 | u32 | 210 | u32 |
| 211 | gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor) | 211 | gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor) |
| @@ -219,7 +219,7 @@ gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor) | |||
| 219 | return 0; | 219 | return 0; |
| 220 | } | 220 | } |
| 221 | 221 | ||
| 222 | EXPORT_SYMBOL(gss_pseudoflavor_to_service); | 222 | EXPORT_SYMBOL_GPL(gss_pseudoflavor_to_service); |
| 223 | 223 | ||
| 224 | char * | 224 | char * |
| 225 | gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service) | 225 | gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service) |
| @@ -233,7 +233,7 @@ gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service) | |||
| 233 | return NULL; | 233 | return NULL; |
| 234 | } | 234 | } |
| 235 | 235 | ||
| 236 | EXPORT_SYMBOL(gss_service_to_auth_domain_name); | 236 | EXPORT_SYMBOL_GPL(gss_service_to_auth_domain_name); |
| 237 | 237 | ||
| 238 | void | 238 | void |
| 239 | gss_mech_put(struct gss_api_mech * gm) | 239 | gss_mech_put(struct gss_api_mech * gm) |
| @@ -242,7 +242,7 @@ gss_mech_put(struct gss_api_mech * gm) | |||
| 242 | module_put(gm->gm_owner); | 242 | module_put(gm->gm_owner); |
| 243 | } | 243 | } |
| 244 | 244 | ||
| 245 | EXPORT_SYMBOL(gss_mech_put); | 245 | EXPORT_SYMBOL_GPL(gss_mech_put); |
| 246 | 246 | ||
| 247 | /* The mech could probably be determined from the token instead, but it's just | 247 | /* The mech could probably be determined from the token instead, but it's just |
| 248 | * as easy for now to pass it in. */ | 248 | * as easy for now to pass it in. */ |
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 81ae3d62a0cc..2278a50c6444 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c | |||
| @@ -332,6 +332,7 @@ struct rsc { | |||
| 332 | struct svc_cred cred; | 332 | struct svc_cred cred; |
| 333 | struct gss_svc_seq_data seqdata; | 333 | struct gss_svc_seq_data seqdata; |
| 334 | struct gss_ctx *mechctx; | 334 | struct gss_ctx *mechctx; |
| 335 | char *client_name; | ||
| 335 | }; | 336 | }; |
| 336 | 337 | ||
| 337 | static struct cache_head *rsc_table[RSC_HASHMAX]; | 338 | static struct cache_head *rsc_table[RSC_HASHMAX]; |
| @@ -346,6 +347,7 @@ static void rsc_free(struct rsc *rsci) | |||
| 346 | gss_delete_sec_context(&rsci->mechctx); | 347 | gss_delete_sec_context(&rsci->mechctx); |
| 347 | if (rsci->cred.cr_group_info) | 348 | if (rsci->cred.cr_group_info) |
| 348 | put_group_info(rsci->cred.cr_group_info); | 349 | put_group_info(rsci->cred.cr_group_info); |
| 350 | kfree(rsci->client_name); | ||
| 349 | } | 351 | } |
| 350 | 352 | ||
| 351 | static void rsc_put(struct kref *ref) | 353 | static void rsc_put(struct kref *ref) |
| @@ -383,6 +385,7 @@ rsc_init(struct cache_head *cnew, struct cache_head *ctmp) | |||
| 383 | tmp->handle.data = NULL; | 385 | tmp->handle.data = NULL; |
| 384 | new->mechctx = NULL; | 386 | new->mechctx = NULL; |
| 385 | new->cred.cr_group_info = NULL; | 387 | new->cred.cr_group_info = NULL; |
| 388 | new->client_name = NULL; | ||
| 386 | } | 389 | } |
| 387 | 390 | ||
| 388 | static void | 391 | static void |
| @@ -397,6 +400,8 @@ update_rsc(struct cache_head *cnew, struct cache_head *ctmp) | |||
| 397 | spin_lock_init(&new->seqdata.sd_lock); | 400 | spin_lock_init(&new->seqdata.sd_lock); |
| 398 | new->cred = tmp->cred; | 401 | new->cred = tmp->cred; |
| 399 | tmp->cred.cr_group_info = NULL; | 402 | tmp->cred.cr_group_info = NULL; |
| 403 | new->client_name = tmp->client_name; | ||
| 404 | tmp->client_name = NULL; | ||
| 400 | } | 405 | } |
| 401 | 406 | ||
| 402 | static struct cache_head * | 407 | static struct cache_head * |
| @@ -486,6 +491,15 @@ static int rsc_parse(struct cache_detail *cd, | |||
| 486 | status = gss_import_sec_context(buf, len, gm, &rsci.mechctx); | 491 | status = gss_import_sec_context(buf, len, gm, &rsci.mechctx); |
| 487 | if (status) | 492 | if (status) |
| 488 | goto out; | 493 | goto out; |
| 494 | |||
| 495 | /* get client name */ | ||
| 496 | len = qword_get(&mesg, buf, mlen); | ||
| 497 | if (len > 0) { | ||
| 498 | rsci.client_name = kstrdup(buf, GFP_KERNEL); | ||
| 499 | if (!rsci.client_name) | ||
| 500 | goto out; | ||
| 501 | } | ||
| 502 | |||
| 489 | } | 503 | } |
| 490 | rsci.h.expiry_time = expiry; | 504 | rsci.h.expiry_time = expiry; |
| 491 | rscp = rsc_update(&rsci, rscp); | 505 | rscp = rsc_update(&rsci, rscp); |
| @@ -746,7 +760,7 @@ u32 svcauth_gss_flavor(struct auth_domain *dom) | |||
| 746 | return gd->pseudoflavor; | 760 | return gd->pseudoflavor; |
| 747 | } | 761 | } |
| 748 | 762 | ||
| 749 | EXPORT_SYMBOL(svcauth_gss_flavor); | 763 | EXPORT_SYMBOL_GPL(svcauth_gss_flavor); |
| 750 | 764 | ||
| 751 | int | 765 | int |
| 752 | svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name) | 766 | svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name) |
| @@ -780,7 +794,7 @@ out: | |||
| 780 | return stat; | 794 | return stat; |
| 781 | } | 795 | } |
| 782 | 796 | ||
| 783 | EXPORT_SYMBOL(svcauth_gss_register_pseudoflavor); | 797 | EXPORT_SYMBOL_GPL(svcauth_gss_register_pseudoflavor); |
| 784 | 798 | ||
| 785 | static inline int | 799 | static inline int |
| 786 | read_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj) | 800 | read_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj) |
| @@ -913,6 +927,16 @@ struct gss_svc_data { | |||
| 913 | struct rsc *rsci; | 927 | struct rsc *rsci; |
| 914 | }; | 928 | }; |
| 915 | 929 | ||
| 930 | char *svc_gss_principal(struct svc_rqst *rqstp) | ||
| 931 | { | ||
| 932 | struct gss_svc_data *gd = (struct gss_svc_data *)rqstp->rq_auth_data; | ||
| 933 | |||
| 934 | if (gd && gd->rsci) | ||
| 935 | return gd->rsci->client_name; | ||
| 936 | return NULL; | ||
| 937 | } | ||
| 938 | EXPORT_SYMBOL_GPL(svc_gss_principal); | ||
| 939 | |||
| 916 | static int | 940 | static int |
| 917 | svcauth_gss_set_client(struct svc_rqst *rqstp) | 941 | svcauth_gss_set_client(struct svc_rqst *rqstp) |
| 918 | { | 942 | { |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 3ca518386d15..836f15c0c4a3 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
| @@ -197,6 +197,12 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru | |||
| 197 | 197 | ||
| 198 | clnt->cl_rtt = &clnt->cl_rtt_default; | 198 | clnt->cl_rtt = &clnt->cl_rtt_default; |
| 199 | rpc_init_rtt(&clnt->cl_rtt_default, clnt->cl_timeout->to_initval); | 199 | rpc_init_rtt(&clnt->cl_rtt_default, clnt->cl_timeout->to_initval); |
| 200 | clnt->cl_principal = NULL; | ||
| 201 | if (args->client_name) { | ||
| 202 | clnt->cl_principal = kstrdup(args->client_name, GFP_KERNEL); | ||
| 203 | if (!clnt->cl_principal) | ||
| 204 | goto out_no_principal; | ||
| 205 | } | ||
| 200 | 206 | ||
| 201 | kref_init(&clnt->cl_kref); | 207 | kref_init(&clnt->cl_kref); |
| 202 | 208 | ||
| @@ -226,6 +232,8 @@ out_no_auth: | |||
| 226 | rpc_put_mount(); | 232 | rpc_put_mount(); |
| 227 | } | 233 | } |
| 228 | out_no_path: | 234 | out_no_path: |
| 235 | kfree(clnt->cl_principal); | ||
| 236 | out_no_principal: | ||
| 229 | rpc_free_iostats(clnt->cl_metrics); | 237 | rpc_free_iostats(clnt->cl_metrics); |
| 230 | out_no_stats: | 238 | out_no_stats: |
| 231 | if (clnt->cl_server != clnt->cl_inline_name) | 239 | if (clnt->cl_server != clnt->cl_inline_name) |
| @@ -354,6 +362,11 @@ rpc_clone_client(struct rpc_clnt *clnt) | |||
| 354 | new->cl_metrics = rpc_alloc_iostats(clnt); | 362 | new->cl_metrics = rpc_alloc_iostats(clnt); |
| 355 | if (new->cl_metrics == NULL) | 363 | if (new->cl_metrics == NULL) |
| 356 | goto out_no_stats; | 364 | goto out_no_stats; |
| 365 | if (clnt->cl_principal) { | ||
| 366 | new->cl_principal = kstrdup(clnt->cl_principal, GFP_KERNEL); | ||
| 367 | if (new->cl_principal == NULL) | ||
| 368 | goto out_no_principal; | ||
| 369 | } | ||
| 357 | kref_init(&new->cl_kref); | 370 | kref_init(&new->cl_kref); |
| 358 | err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name); | 371 | err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name); |
| 359 | if (err != 0) | 372 | if (err != 0) |
| @@ -366,6 +379,8 @@ rpc_clone_client(struct rpc_clnt *clnt) | |||
| 366 | rpciod_up(); | 379 | rpciod_up(); |
| 367 | return new; | 380 | return new; |
| 368 | out_no_path: | 381 | out_no_path: |
| 382 | kfree(new->cl_principal); | ||
| 383 | out_no_principal: | ||
| 369 | rpc_free_iostats(new->cl_metrics); | 384 | rpc_free_iostats(new->cl_metrics); |
| 370 | out_no_stats: | 385 | out_no_stats: |
| 371 | kfree(new); | 386 | kfree(new); |
| @@ -417,6 +432,7 @@ rpc_free_client(struct kref *kref) | |||
| 417 | out_free: | 432 | out_free: |
| 418 | rpc_unregister_client(clnt); | 433 | rpc_unregister_client(clnt); |
| 419 | rpc_free_iostats(clnt->cl_metrics); | 434 | rpc_free_iostats(clnt->cl_metrics); |
| 435 | kfree(clnt->cl_principal); | ||
| 420 | clnt->cl_metrics = NULL; | 436 | clnt->cl_metrics = NULL; |
| 421 | xprt_put(clnt->cl_xprt); | 437 | xprt_put(clnt->cl_xprt); |
| 422 | rpciod_down(); | 438 | rpciod_down(); |
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 23a2b8f6dc49..192453248870 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c | |||
| @@ -113,7 +113,7 @@ out: | |||
| 113 | wake_up(&rpci->waitq); | 113 | wake_up(&rpci->waitq); |
| 114 | return res; | 114 | return res; |
| 115 | } | 115 | } |
| 116 | EXPORT_SYMBOL(rpc_queue_upcall); | 116 | EXPORT_SYMBOL_GPL(rpc_queue_upcall); |
| 117 | 117 | ||
| 118 | static inline void | 118 | static inline void |
| 119 | rpc_inode_setowner(struct inode *inode, void *private) | 119 | rpc_inode_setowner(struct inode *inode, void *private) |
| @@ -126,13 +126,14 @@ rpc_close_pipes(struct inode *inode) | |||
| 126 | { | 126 | { |
| 127 | struct rpc_inode *rpci = RPC_I(inode); | 127 | struct rpc_inode *rpci = RPC_I(inode); |
| 128 | struct rpc_pipe_ops *ops; | 128 | struct rpc_pipe_ops *ops; |
| 129 | int need_release; | ||
| 129 | 130 | ||
| 130 | mutex_lock(&inode->i_mutex); | 131 | mutex_lock(&inode->i_mutex); |
| 131 | ops = rpci->ops; | 132 | ops = rpci->ops; |
| 132 | if (ops != NULL) { | 133 | if (ops != NULL) { |
| 133 | LIST_HEAD(free_list); | 134 | LIST_HEAD(free_list); |
| 134 | |||
| 135 | spin_lock(&inode->i_lock); | 135 | spin_lock(&inode->i_lock); |
| 136 | need_release = rpci->nreaders != 0 || rpci->nwriters != 0; | ||
| 136 | rpci->nreaders = 0; | 137 | rpci->nreaders = 0; |
| 137 | list_splice_init(&rpci->in_upcall, &free_list); | 138 | list_splice_init(&rpci->in_upcall, &free_list); |
| 138 | list_splice_init(&rpci->pipe, &free_list); | 139 | list_splice_init(&rpci->pipe, &free_list); |
| @@ -141,7 +142,7 @@ rpc_close_pipes(struct inode *inode) | |||
| 141 | spin_unlock(&inode->i_lock); | 142 | spin_unlock(&inode->i_lock); |
| 142 | rpc_purge_list(rpci, &free_list, ops->destroy_msg, -EPIPE); | 143 | rpc_purge_list(rpci, &free_list, ops->destroy_msg, -EPIPE); |
| 143 | rpci->nwriters = 0; | 144 | rpci->nwriters = 0; |
| 144 | if (ops->release_pipe) | 145 | if (need_release && ops->release_pipe) |
| 145 | ops->release_pipe(inode); | 146 | ops->release_pipe(inode); |
| 146 | cancel_delayed_work_sync(&rpci->queue_timeout); | 147 | cancel_delayed_work_sync(&rpci->queue_timeout); |
| 147 | } | 148 | } |
| @@ -169,16 +170,24 @@ static int | |||
| 169 | rpc_pipe_open(struct inode *inode, struct file *filp) | 170 | rpc_pipe_open(struct inode *inode, struct file *filp) |
| 170 | { | 171 | { |
| 171 | struct rpc_inode *rpci = RPC_I(inode); | 172 | struct rpc_inode *rpci = RPC_I(inode); |
| 173 | int first_open; | ||
| 172 | int res = -ENXIO; | 174 | int res = -ENXIO; |
| 173 | 175 | ||
| 174 | mutex_lock(&inode->i_mutex); | 176 | mutex_lock(&inode->i_mutex); |
| 175 | if (rpci->ops != NULL) { | 177 | if (rpci->ops == NULL) |
| 176 | if (filp->f_mode & FMODE_READ) | 178 | goto out; |
| 177 | rpci->nreaders ++; | 179 | first_open = rpci->nreaders == 0 && rpci->nwriters == 0; |
| 178 | if (filp->f_mode & FMODE_WRITE) | 180 | if (first_open && rpci->ops->open_pipe) { |
| 179 | rpci->nwriters ++; | 181 | res = rpci->ops->open_pipe(inode); |
| 180 | res = 0; | 182 | if (res) |
| 183 | goto out; | ||
| 181 | } | 184 | } |
| 185 | if (filp->f_mode & FMODE_READ) | ||
| 186 | rpci->nreaders++; | ||
| 187 | if (filp->f_mode & FMODE_WRITE) | ||
| 188 | rpci->nwriters++; | ||
| 189 | res = 0; | ||
| 190 | out: | ||
| 182 | mutex_unlock(&inode->i_mutex); | 191 | mutex_unlock(&inode->i_mutex); |
| 183 | return res; | 192 | return res; |
| 184 | } | 193 | } |
| @@ -188,6 +197,7 @@ rpc_pipe_release(struct inode *inode, struct file *filp) | |||
| 188 | { | 197 | { |
| 189 | struct rpc_inode *rpci = RPC_I(inode); | 198 | struct rpc_inode *rpci = RPC_I(inode); |
| 190 | struct rpc_pipe_msg *msg; | 199 | struct rpc_pipe_msg *msg; |
| 200 | int last_close; | ||
| 191 | 201 | ||
| 192 | mutex_lock(&inode->i_mutex); | 202 | mutex_lock(&inode->i_mutex); |
| 193 | if (rpci->ops == NULL) | 203 | if (rpci->ops == NULL) |
| @@ -214,7 +224,8 @@ rpc_pipe_release(struct inode *inode, struct file *filp) | |||
| 214 | rpci->ops->destroy_msg, -EAGAIN); | 224 | rpci->ops->destroy_msg, -EAGAIN); |
| 215 | } | 225 | } |
| 216 | } | 226 | } |
| 217 | if (rpci->ops->release_pipe) | 227 | last_close = rpci->nwriters == 0 && rpci->nreaders == 0; |
| 228 | if (last_close && rpci->ops->release_pipe) | ||
| 218 | rpci->ops->release_pipe(inode); | 229 | rpci->ops->release_pipe(inode); |
| 219 | out: | 230 | out: |
| 220 | mutex_unlock(&inode->i_mutex); | 231 | mutex_unlock(&inode->i_mutex); |
| @@ -396,6 +407,7 @@ enum { | |||
| 396 | RPCAUTH_nfs, | 407 | RPCAUTH_nfs, |
| 397 | RPCAUTH_portmap, | 408 | RPCAUTH_portmap, |
| 398 | RPCAUTH_statd, | 409 | RPCAUTH_statd, |
| 410 | RPCAUTH_nfsd4_cb, | ||
| 399 | RPCAUTH_RootEOF | 411 | RPCAUTH_RootEOF |
| 400 | }; | 412 | }; |
| 401 | 413 | ||
| @@ -429,6 +441,10 @@ static struct rpc_filelist files[] = { | |||
| 429 | .name = "statd", | 441 | .name = "statd", |
| 430 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | 442 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, |
| 431 | }, | 443 | }, |
| 444 | [RPCAUTH_nfsd4_cb] = { | ||
| 445 | .name = "nfsd4_cb", | ||
| 446 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
| 447 | }, | ||
| 432 | }; | 448 | }; |
| 433 | 449 | ||
| 434 | enum { | 450 | enum { |
| @@ -748,7 +764,7 @@ rpc_rmdir(struct dentry *dentry) | |||
| 748 | * @name: name of pipe | 764 | * @name: name of pipe |
| 749 | * @private: private data to associate with the pipe, for the caller's use | 765 | * @private: private data to associate with the pipe, for the caller's use |
| 750 | * @ops: operations defining the behavior of the pipe: upcall, downcall, | 766 | * @ops: operations defining the behavior of the pipe: upcall, downcall, |
| 751 | * release_pipe, and destroy_msg. | 767 | * release_pipe, open_pipe, and destroy_msg. |
| 752 | * @flags: rpc_inode flags | 768 | * @flags: rpc_inode flags |
| 753 | * | 769 | * |
| 754 | * Data is made available for userspace to read by calls to | 770 | * Data is made available for userspace to read by calls to |
| @@ -808,7 +824,7 @@ err_dput: | |||
| 808 | -ENOMEM); | 824 | -ENOMEM); |
| 809 | goto out; | 825 | goto out; |
| 810 | } | 826 | } |
| 811 | EXPORT_SYMBOL(rpc_mkpipe); | 827 | EXPORT_SYMBOL_GPL(rpc_mkpipe); |
| 812 | 828 | ||
| 813 | /** | 829 | /** |
| 814 | * rpc_unlink - remove a pipe | 830 | * rpc_unlink - remove a pipe |
| @@ -839,7 +855,7 @@ rpc_unlink(struct dentry *dentry) | |||
| 839 | dput(parent); | 855 | dput(parent); |
| 840 | return error; | 856 | return error; |
| 841 | } | 857 | } |
| 842 | EXPORT_SYMBOL(rpc_unlink); | 858 | EXPORT_SYMBOL_GPL(rpc_unlink); |
| 843 | 859 | ||
| 844 | /* | 860 | /* |
| 845 | * populate the filesystem | 861 | * populate the filesystem |
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index 79a55d56cc98..406e26de584e 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c | |||
| @@ -28,7 +28,7 @@ xdr_encode_netobj(__be32 *p, const struct xdr_netobj *obj) | |||
| 28 | memcpy(p, obj->data, obj->len); | 28 | memcpy(p, obj->data, obj->len); |
| 29 | return p + XDR_QUADLEN(obj->len); | 29 | return p + XDR_QUADLEN(obj->len); |
| 30 | } | 30 | } |
| 31 | EXPORT_SYMBOL(xdr_encode_netobj); | 31 | EXPORT_SYMBOL_GPL(xdr_encode_netobj); |
| 32 | 32 | ||
| 33 | __be32 * | 33 | __be32 * |
| 34 | xdr_decode_netobj(__be32 *p, struct xdr_netobj *obj) | 34 | xdr_decode_netobj(__be32 *p, struct xdr_netobj *obj) |
| @@ -41,7 +41,7 @@ xdr_decode_netobj(__be32 *p, struct xdr_netobj *obj) | |||
| 41 | obj->data = (u8 *) p; | 41 | obj->data = (u8 *) p; |
| 42 | return p + XDR_QUADLEN(len); | 42 | return p + XDR_QUADLEN(len); |
| 43 | } | 43 | } |
| 44 | EXPORT_SYMBOL(xdr_decode_netobj); | 44 | EXPORT_SYMBOL_GPL(xdr_decode_netobj); |
| 45 | 45 | ||
| 46 | /** | 46 | /** |
| 47 | * xdr_encode_opaque_fixed - Encode fixed length opaque data | 47 | * xdr_encode_opaque_fixed - Encode fixed length opaque data |
| @@ -71,7 +71,7 @@ __be32 *xdr_encode_opaque_fixed(__be32 *p, const void *ptr, unsigned int nbytes) | |||
| 71 | } | 71 | } |
| 72 | return p; | 72 | return p; |
| 73 | } | 73 | } |
| 74 | EXPORT_SYMBOL(xdr_encode_opaque_fixed); | 74 | EXPORT_SYMBOL_GPL(xdr_encode_opaque_fixed); |
| 75 | 75 | ||
| 76 | /** | 76 | /** |
| 77 | * xdr_encode_opaque - Encode variable length opaque data | 77 | * xdr_encode_opaque - Encode variable length opaque data |
| @@ -86,14 +86,14 @@ __be32 *xdr_encode_opaque(__be32 *p, const void *ptr, unsigned int nbytes) | |||
| 86 | *p++ = htonl(nbytes); | 86 | *p++ = htonl(nbytes); |
| 87 | return xdr_encode_opaque_fixed(p, ptr, nbytes); | 87 | return xdr_encode_opaque_fixed(p, ptr, nbytes); |
| 88 | } | 88 | } |
| 89 | EXPORT_SYMBOL(xdr_encode_opaque); | 89 | EXPORT_SYMBOL_GPL(xdr_encode_opaque); |
| 90 | 90 | ||
| 91 | __be32 * | 91 | __be32 * |
| 92 | xdr_encode_string(__be32 *p, const char *string) | 92 | xdr_encode_string(__be32 *p, const char *string) |
| 93 | { | 93 | { |
| 94 | return xdr_encode_array(p, string, strlen(string)); | 94 | return xdr_encode_array(p, string, strlen(string)); |
| 95 | } | 95 | } |
| 96 | EXPORT_SYMBOL(xdr_encode_string); | 96 | EXPORT_SYMBOL_GPL(xdr_encode_string); |
| 97 | 97 | ||
| 98 | __be32 * | 98 | __be32 * |
| 99 | xdr_decode_string_inplace(__be32 *p, char **sp, | 99 | xdr_decode_string_inplace(__be32 *p, char **sp, |
| @@ -108,7 +108,7 @@ xdr_decode_string_inplace(__be32 *p, char **sp, | |||
| 108 | *sp = (char *) p; | 108 | *sp = (char *) p; |
| 109 | return p + XDR_QUADLEN(len); | 109 | return p + XDR_QUADLEN(len); |
| 110 | } | 110 | } |
| 111 | EXPORT_SYMBOL(xdr_decode_string_inplace); | 111 | EXPORT_SYMBOL_GPL(xdr_decode_string_inplace); |
| 112 | 112 | ||
| 113 | void | 113 | void |
| 114 | xdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base, | 114 | xdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base, |
| @@ -136,7 +136,7 @@ xdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base, | |||
| 136 | xdr->buflen += len; | 136 | xdr->buflen += len; |
| 137 | xdr->len += len; | 137 | xdr->len += len; |
| 138 | } | 138 | } |
| 139 | EXPORT_SYMBOL(xdr_encode_pages); | 139 | EXPORT_SYMBOL_GPL(xdr_encode_pages); |
| 140 | 140 | ||
| 141 | void | 141 | void |
| 142 | xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset, | 142 | xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset, |
| @@ -158,7 +158,7 @@ xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset, | |||
| 158 | 158 | ||
| 159 | xdr->buflen += len; | 159 | xdr->buflen += len; |
| 160 | } | 160 | } |
| 161 | EXPORT_SYMBOL(xdr_inline_pages); | 161 | EXPORT_SYMBOL_GPL(xdr_inline_pages); |
| 162 | 162 | ||
| 163 | /* | 163 | /* |
| 164 | * Helper routines for doing 'memmove' like operations on a struct xdr_buf | 164 | * Helper routines for doing 'memmove' like operations on a struct xdr_buf |
| @@ -428,7 +428,7 @@ xdr_shift_buf(struct xdr_buf *buf, size_t len) | |||
| 428 | { | 428 | { |
| 429 | xdr_shrink_bufhead(buf, len); | 429 | xdr_shrink_bufhead(buf, len); |
| 430 | } | 430 | } |
| 431 | EXPORT_SYMBOL(xdr_shift_buf); | 431 | EXPORT_SYMBOL_GPL(xdr_shift_buf); |
| 432 | 432 | ||
| 433 | /** | 433 | /** |
| 434 | * xdr_init_encode - Initialize a struct xdr_stream for sending data. | 434 | * xdr_init_encode - Initialize a struct xdr_stream for sending data. |
| @@ -465,7 +465,7 @@ void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p) | |||
| 465 | iov->iov_len += len; | 465 | iov->iov_len += len; |
| 466 | } | 466 | } |
| 467 | } | 467 | } |
| 468 | EXPORT_SYMBOL(xdr_init_encode); | 468 | EXPORT_SYMBOL_GPL(xdr_init_encode); |
| 469 | 469 | ||
| 470 | /** | 470 | /** |
| 471 | * xdr_reserve_space - Reserve buffer space for sending | 471 | * xdr_reserve_space - Reserve buffer space for sending |
| @@ -492,7 +492,7 @@ __be32 * xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes) | |||
| 492 | xdr->buf->len += nbytes; | 492 | xdr->buf->len += nbytes; |
| 493 | return p; | 493 | return p; |
| 494 | } | 494 | } |
| 495 | EXPORT_SYMBOL(xdr_reserve_space); | 495 | EXPORT_SYMBOL_GPL(xdr_reserve_space); |
| 496 | 496 | ||
| 497 | /** | 497 | /** |
| 498 | * xdr_write_pages - Insert a list of pages into an XDR buffer for sending | 498 | * xdr_write_pages - Insert a list of pages into an XDR buffer for sending |
| @@ -527,7 +527,7 @@ void xdr_write_pages(struct xdr_stream *xdr, struct page **pages, unsigned int b | |||
| 527 | buf->buflen += len; | 527 | buf->buflen += len; |
| 528 | buf->len += len; | 528 | buf->len += len; |
| 529 | } | 529 | } |
| 530 | EXPORT_SYMBOL(xdr_write_pages); | 530 | EXPORT_SYMBOL_GPL(xdr_write_pages); |
| 531 | 531 | ||
| 532 | /** | 532 | /** |
| 533 | * xdr_init_decode - Initialize an xdr_stream for decoding data. | 533 | * xdr_init_decode - Initialize an xdr_stream for decoding data. |
| @@ -547,7 +547,7 @@ void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p) | |||
| 547 | xdr->p = p; | 547 | xdr->p = p; |
| 548 | xdr->end = (__be32 *)((char *)iov->iov_base + len); | 548 | xdr->end = (__be32 *)((char *)iov->iov_base + len); |
| 549 | } | 549 | } |
| 550 | EXPORT_SYMBOL(xdr_init_decode); | 550 | EXPORT_SYMBOL_GPL(xdr_init_decode); |
| 551 | 551 | ||
| 552 | /** | 552 | /** |
| 553 | * xdr_inline_decode - Retrieve non-page XDR data to decode | 553 | * xdr_inline_decode - Retrieve non-page XDR data to decode |
| @@ -569,7 +569,7 @@ __be32 * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes) | |||
| 569 | xdr->p = q; | 569 | xdr->p = q; |
| 570 | return p; | 570 | return p; |
| 571 | } | 571 | } |
| 572 | EXPORT_SYMBOL(xdr_inline_decode); | 572 | EXPORT_SYMBOL_GPL(xdr_inline_decode); |
| 573 | 573 | ||
| 574 | /** | 574 | /** |
| 575 | * xdr_read_pages - Ensure page-based XDR data to decode is aligned at current pointer position | 575 | * xdr_read_pages - Ensure page-based XDR data to decode is aligned at current pointer position |
| @@ -613,7 +613,7 @@ void xdr_read_pages(struct xdr_stream *xdr, unsigned int len) | |||
| 613 | xdr->p = (__be32 *)((char *)iov->iov_base + padding); | 613 | xdr->p = (__be32 *)((char *)iov->iov_base + padding); |
| 614 | xdr->end = (__be32 *)((char *)iov->iov_base + end); | 614 | xdr->end = (__be32 *)((char *)iov->iov_base + end); |
| 615 | } | 615 | } |
| 616 | EXPORT_SYMBOL(xdr_read_pages); | 616 | EXPORT_SYMBOL_GPL(xdr_read_pages); |
| 617 | 617 | ||
| 618 | /** | 618 | /** |
| 619 | * xdr_enter_page - decode data from the XDR page | 619 | * xdr_enter_page - decode data from the XDR page |
| @@ -638,7 +638,7 @@ void xdr_enter_page(struct xdr_stream *xdr, unsigned int len) | |||
| 638 | xdr->p = (__be32 *)(kaddr + xdr->buf->page_base); | 638 | xdr->p = (__be32 *)(kaddr + xdr->buf->page_base); |
| 639 | xdr->end = (__be32 *)((char *)xdr->p + len); | 639 | xdr->end = (__be32 *)((char *)xdr->p + len); |
| 640 | } | 640 | } |
| 641 | EXPORT_SYMBOL(xdr_enter_page); | 641 | EXPORT_SYMBOL_GPL(xdr_enter_page); |
| 642 | 642 | ||
| 643 | static struct kvec empty_iov = {.iov_base = NULL, .iov_len = 0}; | 643 | static struct kvec empty_iov = {.iov_base = NULL, .iov_len = 0}; |
| 644 | 644 | ||
| @@ -650,7 +650,7 @@ xdr_buf_from_iov(struct kvec *iov, struct xdr_buf *buf) | |||
| 650 | buf->page_len = 0; | 650 | buf->page_len = 0; |
| 651 | buf->buflen = buf->len = iov->iov_len; | 651 | buf->buflen = buf->len = iov->iov_len; |
| 652 | } | 652 | } |
| 653 | EXPORT_SYMBOL(xdr_buf_from_iov); | 653 | EXPORT_SYMBOL_GPL(xdr_buf_from_iov); |
| 654 | 654 | ||
| 655 | /* Sets subbuf to the portion of buf of length len beginning base bytes | 655 | /* Sets subbuf to the portion of buf of length len beginning base bytes |
| 656 | * from the start of buf. Returns -1 if base of length are out of bounds. */ | 656 | * from the start of buf. Returns -1 if base of length are out of bounds. */ |
| @@ -699,7 +699,7 @@ xdr_buf_subsegment(struct xdr_buf *buf, struct xdr_buf *subbuf, | |||
| 699 | return -1; | 699 | return -1; |
| 700 | return 0; | 700 | return 0; |
| 701 | } | 701 | } |
| 702 | EXPORT_SYMBOL(xdr_buf_subsegment); | 702 | EXPORT_SYMBOL_GPL(xdr_buf_subsegment); |
| 703 | 703 | ||
| 704 | static void __read_bytes_from_xdr_buf(struct xdr_buf *subbuf, void *obj, unsigned int len) | 704 | static void __read_bytes_from_xdr_buf(struct xdr_buf *subbuf, void *obj, unsigned int len) |
| 705 | { | 705 | { |
| @@ -730,7 +730,7 @@ int read_bytes_from_xdr_buf(struct xdr_buf *buf, unsigned int base, void *obj, u | |||
| 730 | __read_bytes_from_xdr_buf(&subbuf, obj, len); | 730 | __read_bytes_from_xdr_buf(&subbuf, obj, len); |
| 731 | return 0; | 731 | return 0; |
| 732 | } | 732 | } |
| 733 | EXPORT_SYMBOL(read_bytes_from_xdr_buf); | 733 | EXPORT_SYMBOL_GPL(read_bytes_from_xdr_buf); |
| 734 | 734 | ||
| 735 | static void __write_bytes_to_xdr_buf(struct xdr_buf *subbuf, void *obj, unsigned int len) | 735 | static void __write_bytes_to_xdr_buf(struct xdr_buf *subbuf, void *obj, unsigned int len) |
| 736 | { | 736 | { |
| @@ -774,7 +774,7 @@ xdr_decode_word(struct xdr_buf *buf, unsigned int base, u32 *obj) | |||
| 774 | *obj = ntohl(raw); | 774 | *obj = ntohl(raw); |
| 775 | return 0; | 775 | return 0; |
| 776 | } | 776 | } |
| 777 | EXPORT_SYMBOL(xdr_decode_word); | 777 | EXPORT_SYMBOL_GPL(xdr_decode_word); |
| 778 | 778 | ||
| 779 | int | 779 | int |
| 780 | xdr_encode_word(struct xdr_buf *buf, unsigned int base, u32 obj) | 780 | xdr_encode_word(struct xdr_buf *buf, unsigned int base, u32 obj) |
| @@ -783,7 +783,7 @@ xdr_encode_word(struct xdr_buf *buf, unsigned int base, u32 obj) | |||
| 783 | 783 | ||
| 784 | return write_bytes_to_xdr_buf(buf, base, &raw, sizeof(obj)); | 784 | return write_bytes_to_xdr_buf(buf, base, &raw, sizeof(obj)); |
| 785 | } | 785 | } |
| 786 | EXPORT_SYMBOL(xdr_encode_word); | 786 | EXPORT_SYMBOL_GPL(xdr_encode_word); |
| 787 | 787 | ||
| 788 | /* If the netobj starting offset bytes from the start of xdr_buf is contained | 788 | /* If the netobj starting offset bytes from the start of xdr_buf is contained |
| 789 | * entirely in the head or the tail, set object to point to it; otherwise | 789 | * entirely in the head or the tail, set object to point to it; otherwise |
| @@ -821,7 +821,7 @@ int xdr_buf_read_netobj(struct xdr_buf *buf, struct xdr_netobj *obj, unsigned in | |||
| 821 | __read_bytes_from_xdr_buf(&subbuf, obj->data, obj->len); | 821 | __read_bytes_from_xdr_buf(&subbuf, obj->data, obj->len); |
| 822 | return 0; | 822 | return 0; |
| 823 | } | 823 | } |
| 824 | EXPORT_SYMBOL(xdr_buf_read_netobj); | 824 | EXPORT_SYMBOL_GPL(xdr_buf_read_netobj); |
| 825 | 825 | ||
| 826 | /* Returns 0 on success, or else a negative error code. */ | 826 | /* Returns 0 on success, or else a negative error code. */ |
| 827 | static int | 827 | static int |
| @@ -1027,7 +1027,7 @@ xdr_decode_array2(struct xdr_buf *buf, unsigned int base, | |||
| 1027 | 1027 | ||
| 1028 | return xdr_xcode_array2(buf, base, desc, 0); | 1028 | return xdr_xcode_array2(buf, base, desc, 0); |
| 1029 | } | 1029 | } |
| 1030 | EXPORT_SYMBOL(xdr_decode_array2); | 1030 | EXPORT_SYMBOL_GPL(xdr_decode_array2); |
| 1031 | 1031 | ||
| 1032 | int | 1032 | int |
| 1033 | xdr_encode_array2(struct xdr_buf *buf, unsigned int base, | 1033 | xdr_encode_array2(struct xdr_buf *buf, unsigned int base, |
| @@ -1039,7 +1039,7 @@ xdr_encode_array2(struct xdr_buf *buf, unsigned int base, | |||
| 1039 | 1039 | ||
| 1040 | return xdr_xcode_array2(buf, base, desc, 1); | 1040 | return xdr_xcode_array2(buf, base, desc, 1); |
| 1041 | } | 1041 | } |
| 1042 | EXPORT_SYMBOL(xdr_encode_array2); | 1042 | EXPORT_SYMBOL_GPL(xdr_encode_array2); |
| 1043 | 1043 | ||
| 1044 | int | 1044 | int |
| 1045 | xdr_process_buf(struct xdr_buf *buf, unsigned int offset, unsigned int len, | 1045 | xdr_process_buf(struct xdr_buf *buf, unsigned int offset, unsigned int len, |
| @@ -1106,5 +1106,5 @@ xdr_process_buf(struct xdr_buf *buf, unsigned int offset, unsigned int len, | |||
| 1106 | out: | 1106 | out: |
| 1107 | return ret; | 1107 | return ret; |
| 1108 | } | 1108 | } |
| 1109 | EXPORT_SYMBOL(xdr_process_buf); | 1109 | EXPORT_SYMBOL_GPL(xdr_process_buf); |
| 1110 | 1110 | ||
