diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-07 16:19:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-07 16:19:36 -0400 |
commit | 5df6b8e65ad0f2eaee202ff002ac00d1ac605315 (patch) | |
tree | 2eff6606f8e39dc1fd7eb8a05feb2a9927151805 | |
parent | fe21ea18c742ab0eb8f6f8ebc543374839a02a87 (diff) | |
parent | 3dce9a5c3a39a664e372886ea86c42ae7ae33dfc (diff) |
Merge branch 'nfs-for-2.6.36' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6
* 'nfs-for-2.6.36' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6: (42 commits)
NFS: NFSv4.1 is no longer a "developer only" feature
NFS: NFS_V4 is no longer an EXPERIMENTAL feature
NFS: Fix /proc/mount for legacy binary interface
NFS: Fix the locking in nfs4_callback_getattr
SUNRPC: Defer deleting the security context until gss_do_free_ctx()
SUNRPC: prevent task_cleanup running on freed xprt
SUNRPC: Reduce asynchronous RPC task stack usage
SUNRPC: Move the bound cred to struct rpc_rqst
SUNRPC: Clean up of rpc_bindcred()
SUNRPC: Move remaining RPC client related task initialisation into clnt.c
SUNRPC: Ensure that rpc_exit() always wakes up a sleeping task
SUNRPC: Make the credential cache hashtable size configurable
SUNRPC: Store the hashtable size in struct rpc_cred_cache
NFS: Ensure the AUTH_UNIX credcache is allocated dynamically
NFS: Fix the NFS users of rpc_restart_call()
SUNRPC: The function rpc_restart_call() should return success/failure
NFSv4: Get rid of the bogus RPC_ASSASSINATED(task) checks
NFSv4: Clean up the process of renewing the NFSv4 lease
NFSv4.1: Handle NFS4ERR_DELAY on SEQUENCE correctly
NFS: nfs_rename() should not have to flush out writebacks
...
41 files changed, 963 insertions, 647 deletions
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig index a43d07e7b924..cc1bb33b59b8 100644 --- a/fs/nfs/Kconfig +++ b/fs/nfs/Kconfig | |||
@@ -61,8 +61,8 @@ config NFS_V3_ACL | |||
61 | If unsure, say N. | 61 | If unsure, say N. |
62 | 62 | ||
63 | config NFS_V4 | 63 | config NFS_V4 |
64 | bool "NFS client support for NFS version 4 (EXPERIMENTAL)" | 64 | bool "NFS client support for NFS version 4" |
65 | depends on NFS_FS && EXPERIMENTAL | 65 | depends on NFS_FS |
66 | select RPCSEC_GSS_KRB5 | 66 | select RPCSEC_GSS_KRB5 |
67 | help | 67 | help |
68 | This option enables support for version 4 of the NFS protocol | 68 | This option enables support for version 4 of the NFS protocol |
@@ -72,16 +72,16 @@ config NFS_V4 | |||
72 | space programs which can be found in the Linux nfs-utils package, | 72 | space programs which can be found in the Linux nfs-utils package, |
73 | available from http://linux-nfs.org/. | 73 | available from http://linux-nfs.org/. |
74 | 74 | ||
75 | If unsure, say N. | 75 | If unsure, say Y. |
76 | 76 | ||
77 | config NFS_V4_1 | 77 | config NFS_V4_1 |
78 | bool "NFS client support for NFSv4.1 (DEVELOPER ONLY)" | 78 | bool "NFS client support for NFSv4.1 (EXPERIMENTAL)" |
79 | depends on NFS_V4 && EXPERIMENTAL | 79 | depends on NFS_V4 && EXPERIMENTAL |
80 | help | 80 | help |
81 | This option enables support for minor version 1 of the NFSv4 protocol | 81 | This option enables support for minor version 1 of the NFSv4 protocol |
82 | (draft-ietf-nfsv4-minorversion1) in the kernel's NFS client. | 82 | (draft-ietf-nfsv4-minorversion1) in the kernel's NFS client. |
83 | 83 | ||
84 | Unless you're an NFS developer, say N. | 84 | If unsure, say N. |
85 | 85 | ||
86 | config ROOT_NFS | 86 | config ROOT_NFS |
87 | bool "Root file system on NFS" | 87 | bool "Root file system on NFS" |
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index a08770a7e857..930d10fecdaf 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -37,8 +37,8 @@ __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres * | |||
37 | if (inode == NULL) | 37 | if (inode == NULL) |
38 | goto out_putclient; | 38 | goto out_putclient; |
39 | nfsi = NFS_I(inode); | 39 | nfsi = NFS_I(inode); |
40 | down_read(&nfsi->rwsem); | 40 | rcu_read_lock(); |
41 | delegation = nfsi->delegation; | 41 | delegation = rcu_dereference(nfsi->delegation); |
42 | if (delegation == NULL || (delegation->type & FMODE_WRITE) == 0) | 42 | if (delegation == NULL || (delegation->type & FMODE_WRITE) == 0) |
43 | goto out_iput; | 43 | goto out_iput; |
44 | res->size = i_size_read(inode); | 44 | res->size = i_size_read(inode); |
@@ -53,7 +53,7 @@ __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres * | |||
53 | args->bitmap[1]; | 53 | args->bitmap[1]; |
54 | res->status = 0; | 54 | res->status = 0; |
55 | out_iput: | 55 | out_iput: |
56 | up_read(&nfsi->rwsem); | 56 | rcu_read_unlock(); |
57 | iput(inode); | 57 | iput(inode); |
58 | out_putclient: | 58 | out_putclient: |
59 | nfs_put_client(clp); | 59 | nfs_put_client(clp); |
@@ -62,16 +62,6 @@ out: | |||
62 | return res->status; | 62 | return res->status; |
63 | } | 63 | } |
64 | 64 | ||
65 | static int (*nfs_validate_delegation_stateid(struct nfs_client *clp))(struct nfs_delegation *, const nfs4_stateid *) | ||
66 | { | ||
67 | #if defined(CONFIG_NFS_V4_1) | ||
68 | if (clp->cl_minorversion > 0) | ||
69 | return nfs41_validate_delegation_stateid; | ||
70 | #endif | ||
71 | return nfs4_validate_delegation_stateid; | ||
72 | } | ||
73 | |||
74 | |||
75 | __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy) | 65 | __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy) |
76 | { | 66 | { |
77 | struct nfs_client *clp; | 67 | struct nfs_client *clp; |
@@ -92,8 +82,7 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy) | |||
92 | inode = nfs_delegation_find_inode(clp, &args->fh); | 82 | inode = nfs_delegation_find_inode(clp, &args->fh); |
93 | if (inode != NULL) { | 83 | if (inode != NULL) { |
94 | /* Set up a helper thread to actually return the delegation */ | 84 | /* Set up a helper thread to actually return the delegation */ |
95 | switch (nfs_async_inode_return_delegation(inode, &args->stateid, | 85 | switch (nfs_async_inode_return_delegation(inode, &args->stateid)) { |
96 | nfs_validate_delegation_stateid(clp))) { | ||
97 | case 0: | 86 | case 0: |
98 | res = 0; | 87 | res = 0; |
99 | break; | 88 | break; |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index d25b5257b7a1..4e7df2adb212 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -150,6 +150,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
150 | clp->cl_boot_time = CURRENT_TIME; | 150 | clp->cl_boot_time = CURRENT_TIME; |
151 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; | 151 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; |
152 | clp->cl_minorversion = cl_init->minorversion; | 152 | clp->cl_minorversion = cl_init->minorversion; |
153 | clp->cl_mvops = nfs_v4_minor_ops[cl_init->minorversion]; | ||
153 | #endif | 154 | #endif |
154 | cred = rpc_lookup_machine_cred(); | 155 | cred = rpc_lookup_machine_cred(); |
155 | if (!IS_ERR(cred)) | 156 | if (!IS_ERR(cred)) |
@@ -178,7 +179,7 @@ static void nfs4_clear_client_minor_version(struct nfs_client *clp) | |||
178 | clp->cl_session = NULL; | 179 | clp->cl_session = NULL; |
179 | } | 180 | } |
180 | 181 | ||
181 | clp->cl_call_sync = _nfs4_call_sync; | 182 | clp->cl_mvops = nfs_v4_minor_ops[0]; |
182 | #endif /* CONFIG_NFS_V4_1 */ | 183 | #endif /* CONFIG_NFS_V4_1 */ |
183 | } | 184 | } |
184 | 185 | ||
@@ -188,7 +189,7 @@ static void nfs4_clear_client_minor_version(struct nfs_client *clp) | |||
188 | static void nfs4_destroy_callback(struct nfs_client *clp) | 189 | static void nfs4_destroy_callback(struct nfs_client *clp) |
189 | { | 190 | { |
190 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | 191 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) |
191 | nfs_callback_down(clp->cl_minorversion); | 192 | nfs_callback_down(clp->cl_mvops->minor_version); |
192 | } | 193 | } |
193 | 194 | ||
194 | static void nfs4_shutdown_client(struct nfs_client *clp) | 195 | static void nfs4_shutdown_client(struct nfs_client *clp) |
@@ -1126,7 +1127,7 @@ static int nfs4_init_callback(struct nfs_client *clp) | |||
1126 | return error; | 1127 | return error; |
1127 | } | 1128 | } |
1128 | 1129 | ||
1129 | error = nfs_callback_up(clp->cl_minorversion, | 1130 | error = nfs_callback_up(clp->cl_mvops->minor_version, |
1130 | clp->cl_rpcclient->cl_xprt); | 1131 | clp->cl_rpcclient->cl_xprt); |
1131 | if (error < 0) { | 1132 | if (error < 0) { |
1132 | dprintk("%s: failed to start callback. Error = %d\n", | 1133 | dprintk("%s: failed to start callback. Error = %d\n", |
@@ -1143,10 +1144,8 @@ static int nfs4_init_callback(struct nfs_client *clp) | |||
1143 | */ | 1144 | */ |
1144 | static int nfs4_init_client_minor_version(struct nfs_client *clp) | 1145 | static int nfs4_init_client_minor_version(struct nfs_client *clp) |
1145 | { | 1146 | { |
1146 | clp->cl_call_sync = _nfs4_call_sync; | ||
1147 | |||
1148 | #if defined(CONFIG_NFS_V4_1) | 1147 | #if defined(CONFIG_NFS_V4_1) |
1149 | if (clp->cl_minorversion) { | 1148 | if (clp->cl_mvops->minor_version) { |
1150 | struct nfs4_session *session = NULL; | 1149 | struct nfs4_session *session = NULL; |
1151 | /* | 1150 | /* |
1152 | * Create the session and mark it expired. | 1151 | * Create the session and mark it expired. |
@@ -1158,7 +1157,13 @@ static int nfs4_init_client_minor_version(struct nfs_client *clp) | |||
1158 | return -ENOMEM; | 1157 | return -ENOMEM; |
1159 | 1158 | ||
1160 | clp->cl_session = session; | 1159 | clp->cl_session = session; |
1161 | clp->cl_call_sync = _nfs4_call_sync_session; | 1160 | /* |
1161 | * The create session reply races with the server back | ||
1162 | * channel probe. Mark the client NFS_CS_SESSION_INITING | ||
1163 | * so that the client back channel can find the | ||
1164 | * nfs_client struct | ||
1165 | */ | ||
1166 | clp->cl_cons_state = NFS_CS_SESSION_INITING; | ||
1162 | } | 1167 | } |
1163 | #endif /* CONFIG_NFS_V4_1 */ | 1168 | #endif /* CONFIG_NFS_V4_1 */ |
1164 | 1169 | ||
@@ -1454,7 +1459,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
1454 | data->authflavor, | 1459 | data->authflavor, |
1455 | parent_server->client->cl_xprt->prot, | 1460 | parent_server->client->cl_xprt->prot, |
1456 | parent_server->client->cl_timeout, | 1461 | parent_server->client->cl_timeout, |
1457 | parent_client->cl_minorversion); | 1462 | parent_client->cl_mvops->minor_version); |
1458 | if (error < 0) | 1463 | if (error < 0) |
1459 | goto error; | 1464 | goto error; |
1460 | 1465 | ||
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 301634543974..b9c3c43cea1d 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -268,14 +268,6 @@ out: | |||
268 | return status; | 268 | return status; |
269 | } | 269 | } |
270 | 270 | ||
271 | /* Sync all data to disk upon delegation return */ | ||
272 | static void nfs_msync_inode(struct inode *inode) | ||
273 | { | ||
274 | filemap_fdatawrite(inode->i_mapping); | ||
275 | nfs_wb_all(inode); | ||
276 | filemap_fdatawait(inode->i_mapping); | ||
277 | } | ||
278 | |||
279 | /* | 271 | /* |
280 | * Basic procedure for returning a delegation to the server | 272 | * Basic procedure for returning a delegation to the server |
281 | */ | 273 | */ |
@@ -367,7 +359,7 @@ int nfs_inode_return_delegation(struct inode *inode) | |||
367 | delegation = nfs_detach_delegation_locked(nfsi, NULL, clp); | 359 | delegation = nfs_detach_delegation_locked(nfsi, NULL, clp); |
368 | spin_unlock(&clp->cl_lock); | 360 | spin_unlock(&clp->cl_lock); |
369 | if (delegation != NULL) { | 361 | if (delegation != NULL) { |
370 | nfs_msync_inode(inode); | 362 | nfs_wb_all(inode); |
371 | err = __nfs_inode_return_delegation(inode, delegation, 1); | 363 | err = __nfs_inode_return_delegation(inode, delegation, 1); |
372 | } | 364 | } |
373 | } | 365 | } |
@@ -471,9 +463,7 @@ void nfs_expire_unreferenced_delegations(struct nfs_client *clp) | |||
471 | /* | 463 | /* |
472 | * Asynchronous delegation recall! | 464 | * Asynchronous delegation recall! |
473 | */ | 465 | */ |
474 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid, | 466 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid) |
475 | int (*validate_stateid)(struct nfs_delegation *delegation, | ||
476 | const nfs4_stateid *stateid)) | ||
477 | { | 467 | { |
478 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; | 468 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; |
479 | struct nfs_delegation *delegation; | 469 | struct nfs_delegation *delegation; |
@@ -481,7 +471,7 @@ int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *s | |||
481 | rcu_read_lock(); | 471 | rcu_read_lock(); |
482 | delegation = rcu_dereference(NFS_I(inode)->delegation); | 472 | delegation = rcu_dereference(NFS_I(inode)->delegation); |
483 | 473 | ||
484 | if (!validate_stateid(delegation, stateid)) { | 474 | if (!clp->cl_mvops->validate_stateid(delegation, stateid)) { |
485 | rcu_read_unlock(); | 475 | rcu_read_unlock(); |
486 | return -ENOENT; | 476 | return -ENOENT; |
487 | } | 477 | } |
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index 69e7b8140122..2026304bda19 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h | |||
@@ -34,9 +34,7 @@ enum { | |||
34 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); | 34 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); |
35 | void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); | 35 | void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); |
36 | int nfs_inode_return_delegation(struct inode *inode); | 36 | int nfs_inode_return_delegation(struct inode *inode); |
37 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid, | 37 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid); |
38 | int (*validate_stateid)(struct nfs_delegation *delegation, | ||
39 | const nfs4_stateid *stateid)); | ||
40 | void nfs_inode_return_delegation_noreclaim(struct inode *inode); | 38 | void nfs_inode_return_delegation_noreclaim(struct inode *inode); |
41 | 39 | ||
42 | 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); |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 832e9e239324..29539ceeb745 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -1652,16 +1652,7 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1652 | } | 1652 | } |
1653 | } | 1653 | } |
1654 | 1654 | ||
1655 | /* | ||
1656 | * ... prune child dentries and writebacks if needed. | ||
1657 | */ | ||
1658 | if (atomic_read(&old_dentry->d_count) > 1) { | ||
1659 | if (S_ISREG(old_inode->i_mode)) | ||
1660 | nfs_wb_all(old_inode); | ||
1661 | shrink_dcache_parent(old_dentry); | ||
1662 | } | ||
1663 | nfs_inode_return_delegation(old_inode); | 1655 | nfs_inode_return_delegation(old_inode); |
1664 | |||
1665 | if (new_inode != NULL) | 1656 | if (new_inode != NULL) |
1666 | nfs_inode_return_delegation(new_inode); | 1657 | nfs_inode_return_delegation(new_inode); |
1667 | 1658 | ||
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index ad4cd31d6050..064a80961677 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -69,6 +69,7 @@ struct nfs_direct_req { | |||
69 | 69 | ||
70 | /* I/O parameters */ | 70 | /* I/O parameters */ |
71 | struct nfs_open_context *ctx; /* file open context info */ | 71 | struct nfs_open_context *ctx; /* file open context info */ |
72 | struct nfs_lock_context *l_ctx; /* Lock context info */ | ||
72 | struct kiocb * iocb; /* controlling i/o request */ | 73 | struct kiocb * iocb; /* controlling i/o request */ |
73 | struct inode * inode; /* target file of i/o */ | 74 | struct inode * inode; /* target file of i/o */ |
74 | 75 | ||
@@ -160,6 +161,7 @@ static inline struct nfs_direct_req *nfs_direct_req_alloc(void) | |||
160 | INIT_LIST_HEAD(&dreq->rewrite_list); | 161 | INIT_LIST_HEAD(&dreq->rewrite_list); |
161 | dreq->iocb = NULL; | 162 | dreq->iocb = NULL; |
162 | dreq->ctx = NULL; | 163 | dreq->ctx = NULL; |
164 | dreq->l_ctx = NULL; | ||
163 | spin_lock_init(&dreq->lock); | 165 | spin_lock_init(&dreq->lock); |
164 | atomic_set(&dreq->io_count, 0); | 166 | atomic_set(&dreq->io_count, 0); |
165 | dreq->count = 0; | 167 | dreq->count = 0; |
@@ -173,6 +175,8 @@ static void nfs_direct_req_free(struct kref *kref) | |||
173 | { | 175 | { |
174 | struct nfs_direct_req *dreq = container_of(kref, struct nfs_direct_req, kref); | 176 | struct nfs_direct_req *dreq = container_of(kref, struct nfs_direct_req, kref); |
175 | 177 | ||
178 | if (dreq->l_ctx != NULL) | ||
179 | nfs_put_lock_context(dreq->l_ctx); | ||
176 | if (dreq->ctx != NULL) | 180 | if (dreq->ctx != NULL) |
177 | put_nfs_open_context(dreq->ctx); | 181 | put_nfs_open_context(dreq->ctx); |
178 | kmem_cache_free(nfs_direct_cachep, dreq); | 182 | kmem_cache_free(nfs_direct_cachep, dreq); |
@@ -336,6 +340,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, | |||
336 | data->cred = msg.rpc_cred; | 340 | data->cred = msg.rpc_cred; |
337 | data->args.fh = NFS_FH(inode); | 341 | data->args.fh = NFS_FH(inode); |
338 | data->args.context = ctx; | 342 | data->args.context = ctx; |
343 | data->args.lock_context = dreq->l_ctx; | ||
339 | data->args.offset = pos; | 344 | data->args.offset = pos; |
340 | data->args.pgbase = pgbase; | 345 | data->args.pgbase = pgbase; |
341 | data->args.pages = data->pagevec; | 346 | data->args.pages = data->pagevec; |
@@ -416,24 +421,28 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, | |||
416 | static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov, | 421 | static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov, |
417 | unsigned long nr_segs, loff_t pos) | 422 | unsigned long nr_segs, loff_t pos) |
418 | { | 423 | { |
419 | ssize_t result = 0; | 424 | ssize_t result = -ENOMEM; |
420 | struct inode *inode = iocb->ki_filp->f_mapping->host; | 425 | struct inode *inode = iocb->ki_filp->f_mapping->host; |
421 | struct nfs_direct_req *dreq; | 426 | struct nfs_direct_req *dreq; |
422 | 427 | ||
423 | dreq = nfs_direct_req_alloc(); | 428 | dreq = nfs_direct_req_alloc(); |
424 | if (!dreq) | 429 | if (dreq == NULL) |
425 | return -ENOMEM; | 430 | goto out; |
426 | 431 | ||
427 | dreq->inode = inode; | 432 | dreq->inode = inode; |
428 | dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); | 433 | dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); |
434 | dreq->l_ctx = nfs_get_lock_context(dreq->ctx); | ||
435 | if (dreq->l_ctx == NULL) | ||
436 | goto out_release; | ||
429 | if (!is_sync_kiocb(iocb)) | 437 | if (!is_sync_kiocb(iocb)) |
430 | dreq->iocb = iocb; | 438 | dreq->iocb = iocb; |
431 | 439 | ||
432 | result = nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos); | 440 | result = nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos); |
433 | if (!result) | 441 | if (!result) |
434 | result = nfs_direct_wait(dreq); | 442 | result = nfs_direct_wait(dreq); |
443 | out_release: | ||
435 | nfs_direct_req_release(dreq); | 444 | nfs_direct_req_release(dreq); |
436 | 445 | out: | |
437 | return result; | 446 | return result; |
438 | } | 447 | } |
439 | 448 | ||
@@ -574,6 +583,7 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) | |||
574 | data->args.offset = 0; | 583 | data->args.offset = 0; |
575 | data->args.count = 0; | 584 | data->args.count = 0; |
576 | data->args.context = dreq->ctx; | 585 | data->args.context = dreq->ctx; |
586 | data->args.lock_context = dreq->l_ctx; | ||
577 | data->res.count = 0; | 587 | data->res.count = 0; |
578 | data->res.fattr = &data->fattr; | 588 | data->res.fattr = &data->fattr; |
579 | data->res.verf = &data->verf; | 589 | data->res.verf = &data->verf; |
@@ -761,6 +771,7 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, | |||
761 | data->cred = msg.rpc_cred; | 771 | data->cred = msg.rpc_cred; |
762 | data->args.fh = NFS_FH(inode); | 772 | data->args.fh = NFS_FH(inode); |
763 | data->args.context = ctx; | 773 | data->args.context = ctx; |
774 | data->args.lock_context = dreq->l_ctx; | ||
764 | data->args.offset = pos; | 775 | data->args.offset = pos; |
765 | data->args.pgbase = pgbase; | 776 | data->args.pgbase = pgbase; |
766 | data->args.pages = data->pagevec; | 777 | data->args.pages = data->pagevec; |
@@ -845,7 +856,7 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov, | |||
845 | unsigned long nr_segs, loff_t pos, | 856 | unsigned long nr_segs, loff_t pos, |
846 | size_t count) | 857 | size_t count) |
847 | { | 858 | { |
848 | ssize_t result = 0; | 859 | ssize_t result = -ENOMEM; |
849 | struct inode *inode = iocb->ki_filp->f_mapping->host; | 860 | struct inode *inode = iocb->ki_filp->f_mapping->host; |
850 | struct nfs_direct_req *dreq; | 861 | struct nfs_direct_req *dreq; |
851 | size_t wsize = NFS_SERVER(inode)->wsize; | 862 | size_t wsize = NFS_SERVER(inode)->wsize; |
@@ -853,7 +864,7 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov, | |||
853 | 864 | ||
854 | dreq = nfs_direct_req_alloc(); | 865 | dreq = nfs_direct_req_alloc(); |
855 | if (!dreq) | 866 | if (!dreq) |
856 | return -ENOMEM; | 867 | goto out; |
857 | nfs_alloc_commit_data(dreq); | 868 | nfs_alloc_commit_data(dreq); |
858 | 869 | ||
859 | if (dreq->commit_data == NULL || count < wsize) | 870 | if (dreq->commit_data == NULL || count < wsize) |
@@ -861,14 +872,18 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov, | |||
861 | 872 | ||
862 | dreq->inode = inode; | 873 | dreq->inode = inode; |
863 | dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); | 874 | dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); |
875 | dreq->l_ctx = nfs_get_lock_context(dreq->ctx); | ||
876 | if (dreq->l_ctx != NULL) | ||
877 | goto out_release; | ||
864 | if (!is_sync_kiocb(iocb)) | 878 | if (!is_sync_kiocb(iocb)) |
865 | dreq->iocb = iocb; | 879 | dreq->iocb = iocb; |
866 | 880 | ||
867 | result = nfs_direct_write_schedule_iovec(dreq, iov, nr_segs, pos, sync); | 881 | result = nfs_direct_write_schedule_iovec(dreq, iov, nr_segs, pos, sync); |
868 | if (!result) | 882 | if (!result) |
869 | result = nfs_direct_wait(dreq); | 883 | result = nfs_direct_wait(dreq); |
884 | out_release: | ||
870 | nfs_direct_req_release(dreq); | 885 | nfs_direct_req_release(dreq); |
871 | 886 | out: | |
872 | return result; | 887 | return result; |
873 | } | 888 | } |
874 | 889 | ||
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index f036153d9f50..2d141a74ae82 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -203,37 +203,11 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin) | |||
203 | } | 203 | } |
204 | 204 | ||
205 | /* | 205 | /* |
206 | * Helper for nfs_file_flush() and nfs_file_fsync() | ||
207 | * | ||
208 | * Notice that it clears the NFS_CONTEXT_ERROR_WRITE before synching to | ||
209 | * disk, but it retrieves and clears ctx->error after synching, despite | ||
210 | * the two being set at the same time in nfs_context_set_write_error(). | ||
211 | * This is because the former is used to notify the _next_ call to | ||
212 | * nfs_file_write() that a write error occured, and hence cause it to | ||
213 | * fall back to doing a synchronous write. | ||
214 | */ | ||
215 | static int nfs_do_fsync(struct nfs_open_context *ctx, struct inode *inode) | ||
216 | { | ||
217 | int have_error, status; | ||
218 | int ret = 0; | ||
219 | |||
220 | have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); | ||
221 | status = nfs_wb_all(inode); | ||
222 | have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); | ||
223 | if (have_error) | ||
224 | ret = xchg(&ctx->error, 0); | ||
225 | if (!ret) | ||
226 | ret = status; | ||
227 | return ret; | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | * Flush all dirty pages, and check for write errors. | 206 | * Flush all dirty pages, and check for write errors. |
232 | */ | 207 | */ |
233 | static int | 208 | static int |
234 | nfs_file_flush(struct file *file, fl_owner_t id) | 209 | nfs_file_flush(struct file *file, fl_owner_t id) |
235 | { | 210 | { |
236 | struct nfs_open_context *ctx = nfs_file_open_context(file); | ||
237 | struct dentry *dentry = file->f_path.dentry; | 211 | struct dentry *dentry = file->f_path.dentry; |
238 | struct inode *inode = dentry->d_inode; | 212 | struct inode *inode = dentry->d_inode; |
239 | 213 | ||
@@ -246,7 +220,7 @@ nfs_file_flush(struct file *file, fl_owner_t id) | |||
246 | return 0; | 220 | return 0; |
247 | 221 | ||
248 | /* Flush writes to the server and return any errors */ | 222 | /* Flush writes to the server and return any errors */ |
249 | return nfs_do_fsync(ctx, inode); | 223 | return vfs_fsync(file, 0); |
250 | } | 224 | } |
251 | 225 | ||
252 | static ssize_t | 226 | static ssize_t |
@@ -321,6 +295,13 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma) | |||
321 | * Flush any dirty pages for this process, and check for write errors. | 295 | * Flush any dirty pages for this process, and check for write errors. |
322 | * The return status from this call provides a reliable indication of | 296 | * The return status from this call provides a reliable indication of |
323 | * whether any write errors occurred for this process. | 297 | * whether any write errors occurred for this process. |
298 | * | ||
299 | * Notice that it clears the NFS_CONTEXT_ERROR_WRITE before synching to | ||
300 | * disk, but it retrieves and clears ctx->error after synching, despite | ||
301 | * the two being set at the same time in nfs_context_set_write_error(). | ||
302 | * This is because the former is used to notify the _next_ call to | ||
303 | * nfs_file_write() that a write error occured, and hence cause it to | ||
304 | * fall back to doing a synchronous write. | ||
324 | */ | 305 | */ |
325 | static int | 306 | static int |
326 | nfs_file_fsync(struct file *file, int datasync) | 307 | nfs_file_fsync(struct file *file, int datasync) |
@@ -328,13 +309,23 @@ nfs_file_fsync(struct file *file, int datasync) | |||
328 | struct dentry *dentry = file->f_path.dentry; | 309 | struct dentry *dentry = file->f_path.dentry; |
329 | struct nfs_open_context *ctx = nfs_file_open_context(file); | 310 | struct nfs_open_context *ctx = nfs_file_open_context(file); |
330 | struct inode *inode = dentry->d_inode; | 311 | struct inode *inode = dentry->d_inode; |
312 | int have_error, status; | ||
313 | int ret = 0; | ||
314 | |||
331 | 315 | ||
332 | dprintk("NFS: fsync file(%s/%s) datasync %d\n", | 316 | dprintk("NFS: fsync file(%s/%s) datasync %d\n", |
333 | dentry->d_parent->d_name.name, dentry->d_name.name, | 317 | dentry->d_parent->d_name.name, dentry->d_name.name, |
334 | datasync); | 318 | datasync); |
335 | 319 | ||
336 | nfs_inc_stats(inode, NFSIOS_VFSFSYNC); | 320 | nfs_inc_stats(inode, NFSIOS_VFSFSYNC); |
337 | return nfs_do_fsync(ctx, inode); | 321 | have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); |
322 | status = nfs_commit_inode(inode, FLUSH_SYNC); | ||
323 | have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); | ||
324 | if (have_error) | ||
325 | ret = xchg(&ctx->error, 0); | ||
326 | if (!ret) | ||
327 | ret = status; | ||
328 | return ret; | ||
338 | } | 329 | } |
339 | 330 | ||
340 | /* | 331 | /* |
@@ -648,7 +639,7 @@ static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, | |||
648 | 639 | ||
649 | /* Return error values for O_DSYNC and IS_SYNC() */ | 640 | /* Return error values for O_DSYNC and IS_SYNC() */ |
650 | if (result >= 0 && nfs_need_sync_write(iocb->ki_filp, inode)) { | 641 | if (result >= 0 && nfs_need_sync_write(iocb->ki_filp, inode)) { |
651 | int err = nfs_do_fsync(nfs_file_open_context(iocb->ki_filp), inode); | 642 | int err = vfs_fsync(iocb->ki_filp, 0); |
652 | if (err < 0) | 643 | if (err < 0) |
653 | result = err; | 644 | result = err; |
654 | } | 645 | } |
@@ -684,7 +675,7 @@ static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe, | |||
684 | written = ret; | 675 | written = ret; |
685 | 676 | ||
686 | if (ret >= 0 && nfs_need_sync_write(filp, inode)) { | 677 | if (ret >= 0 && nfs_need_sync_write(filp, inode)) { |
687 | int err = nfs_do_fsync(nfs_file_open_context(filp), inode); | 678 | int err = vfs_fsync(filp, 0); |
688 | if (err < 0) | 679 | if (err < 0) |
689 | ret = err; | 680 | ret = err; |
690 | } | 681 | } |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 099b3518feea..581d8f081e68 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -413,10 +413,8 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
413 | return 0; | 413 | return 0; |
414 | 414 | ||
415 | /* Write all dirty data */ | 415 | /* Write all dirty data */ |
416 | if (S_ISREG(inode->i_mode)) { | 416 | if (S_ISREG(inode->i_mode)) |
417 | filemap_write_and_wait(inode->i_mapping); | ||
418 | nfs_wb_all(inode); | 417 | nfs_wb_all(inode); |
419 | } | ||
420 | 418 | ||
421 | fattr = nfs_alloc_fattr(); | 419 | fattr = nfs_alloc_fattr(); |
422 | if (fattr == NULL) | 420 | if (fattr == NULL) |
@@ -530,6 +528,68 @@ out: | |||
530 | return err; | 528 | return err; |
531 | } | 529 | } |
532 | 530 | ||
531 | static void nfs_init_lock_context(struct nfs_lock_context *l_ctx) | ||
532 | { | ||
533 | atomic_set(&l_ctx->count, 1); | ||
534 | l_ctx->lockowner = current->files; | ||
535 | l_ctx->pid = current->tgid; | ||
536 | INIT_LIST_HEAD(&l_ctx->list); | ||
537 | } | ||
538 | |||
539 | static struct nfs_lock_context *__nfs_find_lock_context(struct nfs_open_context *ctx) | ||
540 | { | ||
541 | struct nfs_lock_context *pos; | ||
542 | |||
543 | list_for_each_entry(pos, &ctx->lock_context.list, list) { | ||
544 | if (pos->lockowner != current->files) | ||
545 | continue; | ||
546 | if (pos->pid != current->tgid) | ||
547 | continue; | ||
548 | atomic_inc(&pos->count); | ||
549 | return pos; | ||
550 | } | ||
551 | return NULL; | ||
552 | } | ||
553 | |||
554 | struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx) | ||
555 | { | ||
556 | struct nfs_lock_context *res, *new = NULL; | ||
557 | struct inode *inode = ctx->path.dentry->d_inode; | ||
558 | |||
559 | spin_lock(&inode->i_lock); | ||
560 | res = __nfs_find_lock_context(ctx); | ||
561 | if (res == NULL) { | ||
562 | spin_unlock(&inode->i_lock); | ||
563 | new = kmalloc(sizeof(*new), GFP_KERNEL); | ||
564 | if (new == NULL) | ||
565 | return NULL; | ||
566 | nfs_init_lock_context(new); | ||
567 | spin_lock(&inode->i_lock); | ||
568 | res = __nfs_find_lock_context(ctx); | ||
569 | if (res == NULL) { | ||
570 | list_add_tail(&new->list, &ctx->lock_context.list); | ||
571 | new->open_context = ctx; | ||
572 | res = new; | ||
573 | new = NULL; | ||
574 | } | ||
575 | } | ||
576 | spin_unlock(&inode->i_lock); | ||
577 | kfree(new); | ||
578 | return res; | ||
579 | } | ||
580 | |||
581 | void nfs_put_lock_context(struct nfs_lock_context *l_ctx) | ||
582 | { | ||
583 | struct nfs_open_context *ctx = l_ctx->open_context; | ||
584 | struct inode *inode = ctx->path.dentry->d_inode; | ||
585 | |||
586 | if (!atomic_dec_and_lock(&l_ctx->count, &inode->i_lock)) | ||
587 | return; | ||
588 | list_del(&l_ctx->list); | ||
589 | spin_unlock(&inode->i_lock); | ||
590 | kfree(l_ctx); | ||
591 | } | ||
592 | |||
533 | /** | 593 | /** |
534 | * nfs_close_context - Common close_context() routine NFSv2/v3 | 594 | * nfs_close_context - Common close_context() routine NFSv2/v3 |
535 | * @ctx: pointer to context | 595 | * @ctx: pointer to context |
@@ -566,11 +626,11 @@ static struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct | |||
566 | path_get(&ctx->path); | 626 | path_get(&ctx->path); |
567 | ctx->cred = get_rpccred(cred); | 627 | ctx->cred = get_rpccred(cred); |
568 | ctx->state = NULL; | 628 | ctx->state = NULL; |
569 | ctx->lockowner = current->files; | ||
570 | ctx->flags = 0; | 629 | ctx->flags = 0; |
571 | ctx->error = 0; | 630 | ctx->error = 0; |
572 | ctx->dir_cookie = 0; | 631 | ctx->dir_cookie = 0; |
573 | atomic_set(&ctx->count, 1); | 632 | nfs_init_lock_context(&ctx->lock_context); |
633 | ctx->lock_context.open_context = ctx; | ||
574 | } | 634 | } |
575 | return ctx; | 635 | return ctx; |
576 | } | 636 | } |
@@ -578,7 +638,7 @@ static struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct | |||
578 | struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx) | 638 | struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx) |
579 | { | 639 | { |
580 | if (ctx != NULL) | 640 | if (ctx != NULL) |
581 | atomic_inc(&ctx->count); | 641 | atomic_inc(&ctx->lock_context.count); |
582 | return ctx; | 642 | return ctx; |
583 | } | 643 | } |
584 | 644 | ||
@@ -586,7 +646,7 @@ static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync) | |||
586 | { | 646 | { |
587 | struct inode *inode = ctx->path.dentry->d_inode; | 647 | struct inode *inode = ctx->path.dentry->d_inode; |
588 | 648 | ||
589 | if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock)) | 649 | if (!atomic_dec_and_lock(&ctx->lock_context.count, &inode->i_lock)) |
590 | return; | 650 | return; |
591 | list_del(&ctx->list); | 651 | list_del(&ctx->list); |
592 | spin_unlock(&inode->i_lock); | 652 | spin_unlock(&inode->i_lock); |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index e70f44b9b3f4..4c2150d86714 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -370,10 +370,9 @@ unsigned int nfs_page_array_len(unsigned int base, size_t len) | |||
370 | * Helper for restarting RPC calls in the possible presence of NFSv4.1 | 370 | * Helper for restarting RPC calls in the possible presence of NFSv4.1 |
371 | * sessions. | 371 | * sessions. |
372 | */ | 372 | */ |
373 | static inline void nfs_restart_rpc(struct rpc_task *task, const struct nfs_client *clp) | 373 | static inline int nfs_restart_rpc(struct rpc_task *task, const struct nfs_client *clp) |
374 | { | 374 | { |
375 | if (nfs4_has_session(clp)) | 375 | if (nfs4_has_session(clp)) |
376 | rpc_restart_call_prepare(task); | 376 | return rpc_restart_call_prepare(task); |
377 | else | 377 | return rpc_restart_call(task); |
378 | rpc_restart_call(task); | ||
379 | } | 378 | } |
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 81cf14257916..db8846a0e82e 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c | |||
@@ -233,7 +233,7 @@ nfs_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs | |||
233 | static int | 233 | static int |
234 | nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) | 234 | nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) |
235 | { | 235 | { |
236 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | 236 | struct rpc_auth *auth = req->rq_cred->cr_auth; |
237 | unsigned int replen; | 237 | unsigned int replen; |
238 | u32 offset = (u32)args->offset; | 238 | u32 offset = (u32)args->offset; |
239 | u32 count = args->count; | 239 | u32 count = args->count; |
@@ -393,8 +393,7 @@ nfs_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_symlinkargs *arg | |||
393 | static int | 393 | static int |
394 | nfs_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs_readdirargs *args) | 394 | nfs_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs_readdirargs *args) |
395 | { | 395 | { |
396 | struct rpc_task *task = req->rq_task; | 396 | struct rpc_auth *auth = req->rq_cred->cr_auth; |
397 | struct rpc_auth *auth = task->tk_msg.rpc_cred->cr_auth; | ||
398 | unsigned int replen; | 397 | unsigned int replen; |
399 | u32 count = args->count; | 398 | u32 count = args->count; |
400 | 399 | ||
@@ -575,7 +574,7 @@ nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res) | |||
575 | static int | 574 | static int |
576 | nfs_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_readlinkargs *args) | 575 | nfs_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_readlinkargs *args) |
577 | { | 576 | { |
578 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | 577 | struct rpc_auth *auth = req->rq_cred->cr_auth; |
579 | unsigned int replen; | 578 | unsigned int replen; |
580 | 579 | ||
581 | p = xdr_encode_fhandle(p, args->fh); | 580 | p = xdr_encode_fhandle(p, args->fh); |
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index 75dcfc7da365..9769704f8ce6 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c | |||
@@ -330,7 +330,7 @@ nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *arg | |||
330 | static int | 330 | static int |
331 | nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) | 331 | nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) |
332 | { | 332 | { |
333 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | 333 | struct rpc_auth *auth = req->rq_cred->cr_auth; |
334 | unsigned int replen; | 334 | unsigned int replen; |
335 | u32 count = args->count; | 335 | u32 count = args->count; |
336 | 336 | ||
@@ -471,7 +471,7 @@ nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args) | |||
471 | static int | 471 | static int |
472 | nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args) | 472 | nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args) |
473 | { | 473 | { |
474 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | 474 | struct rpc_auth *auth = req->rq_cred->cr_auth; |
475 | unsigned int replen; | 475 | unsigned int replen; |
476 | u32 count = args->count; | 476 | u32 count = args->count; |
477 | 477 | ||
@@ -675,7 +675,7 @@ static int | |||
675 | nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p, | 675 | nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p, |
676 | struct nfs3_getaclargs *args) | 676 | struct nfs3_getaclargs *args) |
677 | { | 677 | { |
678 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | 678 | struct rpc_auth *auth = req->rq_cred->cr_auth; |
679 | unsigned int replen; | 679 | unsigned int replen; |
680 | 680 | ||
681 | p = xdr_encode_fhandle(p, args->fh); | 681 | p = xdr_encode_fhandle(p, args->fh); |
@@ -802,7 +802,7 @@ nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res) | |||
802 | static int | 802 | static int |
803 | nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args) | 803 | nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args) |
804 | { | 804 | { |
805 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | 805 | struct rpc_auth *auth = req->rq_cred->cr_auth; |
806 | unsigned int replen; | 806 | unsigned int replen; |
807 | 807 | ||
808 | p = xdr_encode_fhandle(p, args->fh); | 808 | p = xdr_encode_fhandle(p, args->fh); |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index c538c6106e16..311e15cc8af0 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -45,10 +45,29 @@ enum nfs4_client_state { | |||
45 | NFS4CLNT_RECLAIM_NOGRACE, | 45 | NFS4CLNT_RECLAIM_NOGRACE, |
46 | NFS4CLNT_DELEGRETURN, | 46 | NFS4CLNT_DELEGRETURN, |
47 | NFS4CLNT_SESSION_RESET, | 47 | NFS4CLNT_SESSION_RESET, |
48 | NFS4CLNT_SESSION_DRAINING, | ||
49 | NFS4CLNT_RECALL_SLOT, | 48 | NFS4CLNT_RECALL_SLOT, |
50 | }; | 49 | }; |
51 | 50 | ||
51 | enum nfs4_session_state { | ||
52 | NFS4_SESSION_INITING, | ||
53 | NFS4_SESSION_DRAINING, | ||
54 | }; | ||
55 | |||
56 | struct nfs4_minor_version_ops { | ||
57 | u32 minor_version; | ||
58 | |||
59 | int (*call_sync)(struct nfs_server *server, | ||
60 | struct rpc_message *msg, | ||
61 | struct nfs4_sequence_args *args, | ||
62 | struct nfs4_sequence_res *res, | ||
63 | int cache_reply); | ||
64 | int (*validate_stateid)(struct nfs_delegation *, | ||
65 | const nfs4_stateid *); | ||
66 | const struct nfs4_state_recovery_ops *reboot_recovery_ops; | ||
67 | const struct nfs4_state_recovery_ops *nograce_recovery_ops; | ||
68 | const struct nfs4_state_maintenance_ops *state_renewal_ops; | ||
69 | }; | ||
70 | |||
52 | /* | 71 | /* |
53 | * struct rpc_sequence ensures that RPC calls are sent in the exact | 72 | * struct rpc_sequence ensures that RPC calls are sent in the exact |
54 | * order that they appear on the list. | 73 | * order that they appear on the list. |
@@ -89,7 +108,6 @@ struct nfs_unique_id { | |||
89 | */ | 108 | */ |
90 | struct nfs4_state_owner { | 109 | struct nfs4_state_owner { |
91 | struct nfs_unique_id so_owner_id; | 110 | struct nfs_unique_id so_owner_id; |
92 | struct nfs_client *so_client; | ||
93 | struct nfs_server *so_server; | 111 | struct nfs_server *so_server; |
94 | struct rb_node so_client_node; | 112 | struct rb_node so_client_node; |
95 | 113 | ||
@@ -99,7 +117,6 @@ struct nfs4_state_owner { | |||
99 | atomic_t so_count; | 117 | atomic_t so_count; |
100 | unsigned long so_flags; | 118 | unsigned long so_flags; |
101 | struct list_head so_states; | 119 | struct list_head so_states; |
102 | struct list_head so_delegations; | ||
103 | struct nfs_seqid_counter so_seqid; | 120 | struct nfs_seqid_counter so_seqid; |
104 | struct rpc_sequence so_sequence; | 121 | struct rpc_sequence so_sequence; |
105 | }; | 122 | }; |
@@ -125,10 +142,20 @@ enum { | |||
125 | * LOCK: one nfs4_state (LOCK) to hold the lock stateid nfs4_state(OPEN) | 142 | * LOCK: one nfs4_state (LOCK) to hold the lock stateid nfs4_state(OPEN) |
126 | */ | 143 | */ |
127 | 144 | ||
145 | struct nfs4_lock_owner { | ||
146 | unsigned int lo_type; | ||
147 | #define NFS4_ANY_LOCK_TYPE (0U) | ||
148 | #define NFS4_FLOCK_LOCK_TYPE (1U << 0) | ||
149 | #define NFS4_POSIX_LOCK_TYPE (1U << 1) | ||
150 | union { | ||
151 | fl_owner_t posix_owner; | ||
152 | pid_t flock_owner; | ||
153 | } lo_u; | ||
154 | }; | ||
155 | |||
128 | struct nfs4_lock_state { | 156 | struct nfs4_lock_state { |
129 | struct list_head ls_locks; /* Other lock stateids */ | 157 | struct list_head ls_locks; /* Other lock stateids */ |
130 | struct nfs4_state * ls_state; /* Pointer to open state */ | 158 | struct nfs4_state * ls_state; /* Pointer to open state */ |
131 | fl_owner_t ls_owner; /* POSIX lock owner */ | ||
132 | #define NFS_LOCK_INITIALIZED 1 | 159 | #define NFS_LOCK_INITIALIZED 1 |
133 | int ls_flags; | 160 | int ls_flags; |
134 | struct nfs_seqid_counter ls_seqid; | 161 | struct nfs_seqid_counter ls_seqid; |
@@ -136,6 +163,7 @@ struct nfs4_lock_state { | |||
136 | struct nfs_unique_id ls_id; | 163 | struct nfs_unique_id ls_id; |
137 | nfs4_stateid ls_stateid; | 164 | nfs4_stateid ls_stateid; |
138 | atomic_t ls_count; | 165 | atomic_t ls_count; |
166 | struct nfs4_lock_owner ls_owner; | ||
139 | }; | 167 | }; |
140 | 168 | ||
141 | /* bits for nfs4_state->flags */ | 169 | /* bits for nfs4_state->flags */ |
@@ -219,11 +247,15 @@ extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nam | |||
219 | extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); | 247 | extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); |
220 | extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | 248 | extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, |
221 | struct nfs4_fs_locations *fs_locations, struct page *page); | 249 | struct nfs4_fs_locations *fs_locations, struct page *page); |
250 | extern void nfs4_release_lockowner(const struct nfs4_lock_state *); | ||
222 | 251 | ||
223 | extern struct nfs4_state_recovery_ops *nfs4_reboot_recovery_ops[]; | ||
224 | extern struct nfs4_state_recovery_ops *nfs4_nograce_recovery_ops[]; | ||
225 | #if defined(CONFIG_NFS_V4_1) | 252 | #if defined(CONFIG_NFS_V4_1) |
226 | extern int nfs4_setup_sequence(struct nfs_client *clp, | 253 | static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *server) |
254 | { | ||
255 | return server->nfs_client->cl_session; | ||
256 | } | ||
257 | |||
258 | extern int nfs4_setup_sequence(const struct nfs_server *server, | ||
227 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, | 259 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, |
228 | int cache_reply, struct rpc_task *task); | 260 | int cache_reply, struct rpc_task *task); |
229 | extern void nfs4_destroy_session(struct nfs4_session *session); | 261 | extern void nfs4_destroy_session(struct nfs4_session *session); |
@@ -234,7 +266,12 @@ extern int nfs4_init_session(struct nfs_server *server); | |||
234 | extern int nfs4_proc_get_lease_time(struct nfs_client *clp, | 266 | extern int nfs4_proc_get_lease_time(struct nfs_client *clp, |
235 | struct nfs_fsinfo *fsinfo); | 267 | struct nfs_fsinfo *fsinfo); |
236 | #else /* CONFIG_NFS_v4_1 */ | 268 | #else /* CONFIG_NFS_v4_1 */ |
237 | static inline int nfs4_setup_sequence(struct nfs_client *clp, | 269 | static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *server) |
270 | { | ||
271 | return NULL; | ||
272 | } | ||
273 | |||
274 | static inline int nfs4_setup_sequence(const struct nfs_server *server, | ||
238 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, | 275 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, |
239 | int cache_reply, struct rpc_task *task) | 276 | int cache_reply, struct rpc_task *task) |
240 | { | 277 | { |
@@ -247,7 +284,7 @@ static inline int nfs4_init_session(struct nfs_server *server) | |||
247 | } | 284 | } |
248 | #endif /* CONFIG_NFS_V4_1 */ | 285 | #endif /* CONFIG_NFS_V4_1 */ |
249 | 286 | ||
250 | extern struct nfs4_state_maintenance_ops *nfs4_state_renewal_ops[]; | 287 | extern const struct nfs4_minor_version_ops *nfs_v4_minor_ops[]; |
251 | 288 | ||
252 | extern const u32 nfs4_fattr_bitmap[2]; | 289 | extern const u32 nfs4_fattr_bitmap[2]; |
253 | extern const u32 nfs4_statfs_bitmap[2]; | 290 | extern const u32 nfs4_statfs_bitmap[2]; |
@@ -284,7 +321,7 @@ extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags) | |||
284 | extern void nfs41_handle_recall_slot(struct nfs_client *clp); | 321 | extern void nfs41_handle_recall_slot(struct nfs_client *clp); |
285 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); | 322 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); |
286 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); | 323 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); |
287 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); | 324 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t, pid_t); |
288 | 325 | ||
289 | extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask); | 326 | extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask); |
290 | extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task); | 327 | extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task); |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 70015dd60a98..7ffbb98ddec3 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -303,15 +303,19 @@ do_state_recovery: | |||
303 | } | 303 | } |
304 | 304 | ||
305 | 305 | ||
306 | static void renew_lease(const struct nfs_server *server, unsigned long timestamp) | 306 | static void do_renew_lease(struct nfs_client *clp, unsigned long timestamp) |
307 | { | 307 | { |
308 | struct nfs_client *clp = server->nfs_client; | ||
309 | spin_lock(&clp->cl_lock); | 308 | spin_lock(&clp->cl_lock); |
310 | if (time_before(clp->cl_last_renewal,timestamp)) | 309 | if (time_before(clp->cl_last_renewal,timestamp)) |
311 | clp->cl_last_renewal = timestamp; | 310 | clp->cl_last_renewal = timestamp; |
312 | spin_unlock(&clp->cl_lock); | 311 | spin_unlock(&clp->cl_lock); |
313 | } | 312 | } |
314 | 313 | ||
314 | static void renew_lease(const struct nfs_server *server, unsigned long timestamp) | ||
315 | { | ||
316 | do_renew_lease(server->nfs_client, timestamp); | ||
317 | } | ||
318 | |||
315 | #if defined(CONFIG_NFS_V4_1) | 319 | #if defined(CONFIG_NFS_V4_1) |
316 | 320 | ||
317 | /* | 321 | /* |
@@ -356,7 +360,7 @@ static void nfs41_check_drain_session_complete(struct nfs4_session *ses) | |||
356 | { | 360 | { |
357 | struct rpc_task *task; | 361 | struct rpc_task *task; |
358 | 362 | ||
359 | if (!test_bit(NFS4CLNT_SESSION_DRAINING, &ses->clp->cl_state)) { | 363 | if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state)) { |
360 | task = rpc_wake_up_next(&ses->fc_slot_table.slot_tbl_waitq); | 364 | task = rpc_wake_up_next(&ses->fc_slot_table.slot_tbl_waitq); |
361 | if (task) | 365 | if (task) |
362 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | 366 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); |
@@ -370,12 +374,11 @@ static void nfs41_check_drain_session_complete(struct nfs4_session *ses) | |||
370 | complete(&ses->complete); | 374 | complete(&ses->complete); |
371 | } | 375 | } |
372 | 376 | ||
373 | static void nfs41_sequence_free_slot(const struct nfs_client *clp, | 377 | static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) |
374 | struct nfs4_sequence_res *res) | ||
375 | { | 378 | { |
376 | struct nfs4_slot_table *tbl; | 379 | struct nfs4_slot_table *tbl; |
377 | 380 | ||
378 | tbl = &clp->cl_session->fc_slot_table; | 381 | tbl = &res->sr_session->fc_slot_table; |
379 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) { | 382 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) { |
380 | /* just wake up the next guy waiting since | 383 | /* just wake up the next guy waiting since |
381 | * we may have not consumed a slot after all */ | 384 | * we may have not consumed a slot after all */ |
@@ -385,18 +388,17 @@ static void nfs41_sequence_free_slot(const struct nfs_client *clp, | |||
385 | 388 | ||
386 | spin_lock(&tbl->slot_tbl_lock); | 389 | spin_lock(&tbl->slot_tbl_lock); |
387 | nfs4_free_slot(tbl, res->sr_slotid); | 390 | nfs4_free_slot(tbl, res->sr_slotid); |
388 | nfs41_check_drain_session_complete(clp->cl_session); | 391 | nfs41_check_drain_session_complete(res->sr_session); |
389 | spin_unlock(&tbl->slot_tbl_lock); | 392 | spin_unlock(&tbl->slot_tbl_lock); |
390 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | 393 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; |
391 | } | 394 | } |
392 | 395 | ||
393 | static void nfs41_sequence_done(struct nfs_client *clp, | 396 | static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) |
394 | struct nfs4_sequence_res *res, | ||
395 | int rpc_status) | ||
396 | { | 397 | { |
397 | unsigned long timestamp; | 398 | unsigned long timestamp; |
398 | struct nfs4_slot_table *tbl; | 399 | struct nfs4_slot_table *tbl; |
399 | struct nfs4_slot *slot; | 400 | struct nfs4_slot *slot; |
401 | struct nfs_client *clp; | ||
400 | 402 | ||
401 | /* | 403 | /* |
402 | * sr_status remains 1 if an RPC level error occurred. The server | 404 | * sr_status remains 1 if an RPC level error occurred. The server |
@@ -411,25 +413,51 @@ static void nfs41_sequence_done(struct nfs_client *clp, | |||
411 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) | 413 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) |
412 | goto out; | 414 | goto out; |
413 | 415 | ||
416 | tbl = &res->sr_session->fc_slot_table; | ||
417 | slot = tbl->slots + res->sr_slotid; | ||
418 | |||
414 | /* Check the SEQUENCE operation status */ | 419 | /* Check the SEQUENCE operation status */ |
415 | if (res->sr_status == 0) { | 420 | switch (res->sr_status) { |
416 | tbl = &clp->cl_session->fc_slot_table; | 421 | case 0: |
417 | slot = tbl->slots + res->sr_slotid; | ||
418 | /* Update the slot's sequence and clientid lease timer */ | 422 | /* Update the slot's sequence and clientid lease timer */ |
419 | ++slot->seq_nr; | 423 | ++slot->seq_nr; |
420 | timestamp = res->sr_renewal_time; | 424 | timestamp = res->sr_renewal_time; |
421 | spin_lock(&clp->cl_lock); | 425 | clp = res->sr_session->clp; |
422 | if (time_before(clp->cl_last_renewal, timestamp)) | 426 | do_renew_lease(clp, timestamp); |
423 | clp->cl_last_renewal = timestamp; | ||
424 | spin_unlock(&clp->cl_lock); | ||
425 | /* Check sequence flags */ | 427 | /* Check sequence flags */ |
426 | if (atomic_read(&clp->cl_count) > 1) | 428 | if (atomic_read(&clp->cl_count) > 1) |
427 | nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags); | 429 | nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags); |
430 | break; | ||
431 | case -NFS4ERR_DELAY: | ||
432 | /* The server detected a resend of the RPC call and | ||
433 | * returned NFS4ERR_DELAY as per Section 2.10.6.2 | ||
434 | * of RFC5661. | ||
435 | */ | ||
436 | dprintk("%s: slot=%d seq=%d: Operation in progress\n", | ||
437 | __func__, res->sr_slotid, slot->seq_nr); | ||
438 | goto out_retry; | ||
439 | default: | ||
440 | /* Just update the slot sequence no. */ | ||
441 | ++slot->seq_nr; | ||
428 | } | 442 | } |
429 | out: | 443 | out: |
430 | /* The session may be reset by one of the error handlers. */ | 444 | /* The session may be reset by one of the error handlers. */ |
431 | dprintk("%s: Error %d free the slot \n", __func__, res->sr_status); | 445 | dprintk("%s: Error %d free the slot \n", __func__, res->sr_status); |
432 | nfs41_sequence_free_slot(clp, res); | 446 | nfs41_sequence_free_slot(res); |
447 | return 1; | ||
448 | out_retry: | ||
449 | if (!rpc_restart_call(task)) | ||
450 | goto out; | ||
451 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | ||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | static int nfs4_sequence_done(struct rpc_task *task, | ||
456 | struct nfs4_sequence_res *res) | ||
457 | { | ||
458 | if (res->sr_session == NULL) | ||
459 | return 1; | ||
460 | return nfs41_sequence_done(task, res); | ||
433 | } | 461 | } |
434 | 462 | ||
435 | /* | 463 | /* |
@@ -480,12 +508,11 @@ static int nfs41_setup_sequence(struct nfs4_session *session, | |||
480 | if (res->sr_slotid != NFS4_MAX_SLOT_TABLE) | 508 | if (res->sr_slotid != NFS4_MAX_SLOT_TABLE) |
481 | return 0; | 509 | return 0; |
482 | 510 | ||
483 | memset(res, 0, sizeof(*res)); | ||
484 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | 511 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; |
485 | tbl = &session->fc_slot_table; | 512 | tbl = &session->fc_slot_table; |
486 | 513 | ||
487 | spin_lock(&tbl->slot_tbl_lock); | 514 | spin_lock(&tbl->slot_tbl_lock); |
488 | if (test_bit(NFS4CLNT_SESSION_DRAINING, &session->clp->cl_state) && | 515 | if (test_bit(NFS4_SESSION_DRAINING, &session->session_state) && |
489 | !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) { | 516 | !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) { |
490 | /* | 517 | /* |
491 | * The state manager will wait until the slot table is empty. | 518 | * The state manager will wait until the slot table is empty. |
@@ -525,6 +552,7 @@ static int nfs41_setup_sequence(struct nfs4_session *session, | |||
525 | res->sr_session = session; | 552 | res->sr_session = session; |
526 | res->sr_slotid = slotid; | 553 | res->sr_slotid = slotid; |
527 | res->sr_renewal_time = jiffies; | 554 | res->sr_renewal_time = jiffies; |
555 | res->sr_status_flags = 0; | ||
528 | /* | 556 | /* |
529 | * sr_status is only set in decode_sequence, and so will remain | 557 | * sr_status is only set in decode_sequence, and so will remain |
530 | * set to 1 if an rpc level failure occurs. | 558 | * set to 1 if an rpc level failure occurs. |
@@ -533,33 +561,33 @@ static int nfs41_setup_sequence(struct nfs4_session *session, | |||
533 | return 0; | 561 | return 0; |
534 | } | 562 | } |
535 | 563 | ||
536 | int nfs4_setup_sequence(struct nfs_client *clp, | 564 | int nfs4_setup_sequence(const struct nfs_server *server, |
537 | struct nfs4_sequence_args *args, | 565 | struct nfs4_sequence_args *args, |
538 | struct nfs4_sequence_res *res, | 566 | struct nfs4_sequence_res *res, |
539 | int cache_reply, | 567 | int cache_reply, |
540 | struct rpc_task *task) | 568 | struct rpc_task *task) |
541 | { | 569 | { |
570 | struct nfs4_session *session = nfs4_get_session(server); | ||
542 | int ret = 0; | 571 | int ret = 0; |
543 | 572 | ||
573 | if (session == NULL) { | ||
574 | args->sa_session = NULL; | ||
575 | res->sr_session = NULL; | ||
576 | goto out; | ||
577 | } | ||
578 | |||
544 | dprintk("--> %s clp %p session %p sr_slotid %d\n", | 579 | dprintk("--> %s clp %p session %p sr_slotid %d\n", |
545 | __func__, clp, clp->cl_session, res->sr_slotid); | 580 | __func__, session->clp, session, res->sr_slotid); |
546 | 581 | ||
547 | if (!nfs4_has_session(clp)) | 582 | ret = nfs41_setup_sequence(session, args, res, cache_reply, |
548 | goto out; | ||
549 | ret = nfs41_setup_sequence(clp->cl_session, args, res, cache_reply, | ||
550 | task); | 583 | task); |
551 | if (ret && ret != -EAGAIN) { | ||
552 | /* terminate rpc task */ | ||
553 | task->tk_status = ret; | ||
554 | task->tk_action = NULL; | ||
555 | } | ||
556 | out: | 584 | out: |
557 | dprintk("<-- %s status=%d\n", __func__, ret); | 585 | dprintk("<-- %s status=%d\n", __func__, ret); |
558 | return ret; | 586 | return ret; |
559 | } | 587 | } |
560 | 588 | ||
561 | struct nfs41_call_sync_data { | 589 | struct nfs41_call_sync_data { |
562 | struct nfs_client *clp; | 590 | const struct nfs_server *seq_server; |
563 | struct nfs4_sequence_args *seq_args; | 591 | struct nfs4_sequence_args *seq_args; |
564 | struct nfs4_sequence_res *seq_res; | 592 | struct nfs4_sequence_res *seq_res; |
565 | int cache_reply; | 593 | int cache_reply; |
@@ -569,9 +597,9 @@ static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata) | |||
569 | { | 597 | { |
570 | struct nfs41_call_sync_data *data = calldata; | 598 | struct nfs41_call_sync_data *data = calldata; |
571 | 599 | ||
572 | dprintk("--> %s data->clp->cl_session %p\n", __func__, | 600 | dprintk("--> %s data->seq_server %p\n", __func__, data->seq_server); |
573 | data->clp->cl_session); | 601 | |
574 | if (nfs4_setup_sequence(data->clp, data->seq_args, | 602 | if (nfs4_setup_sequence(data->seq_server, data->seq_args, |
575 | data->seq_res, data->cache_reply, task)) | 603 | data->seq_res, data->cache_reply, task)) |
576 | return; | 604 | return; |
577 | rpc_call_start(task); | 605 | rpc_call_start(task); |
@@ -587,7 +615,7 @@ static void nfs41_call_sync_done(struct rpc_task *task, void *calldata) | |||
587 | { | 615 | { |
588 | struct nfs41_call_sync_data *data = calldata; | 616 | struct nfs41_call_sync_data *data = calldata; |
589 | 617 | ||
590 | nfs41_sequence_done(data->clp, data->seq_res, task->tk_status); | 618 | nfs41_sequence_done(task, data->seq_res); |
591 | } | 619 | } |
592 | 620 | ||
593 | struct rpc_call_ops nfs41_call_sync_ops = { | 621 | struct rpc_call_ops nfs41_call_sync_ops = { |
@@ -600,8 +628,7 @@ struct rpc_call_ops nfs41_call_priv_sync_ops = { | |||
600 | .rpc_call_done = nfs41_call_sync_done, | 628 | .rpc_call_done = nfs41_call_sync_done, |
601 | }; | 629 | }; |
602 | 630 | ||
603 | static int nfs4_call_sync_sequence(struct nfs_client *clp, | 631 | static int nfs4_call_sync_sequence(struct nfs_server *server, |
604 | struct rpc_clnt *clnt, | ||
605 | struct rpc_message *msg, | 632 | struct rpc_message *msg, |
606 | struct nfs4_sequence_args *args, | 633 | struct nfs4_sequence_args *args, |
607 | struct nfs4_sequence_res *res, | 634 | struct nfs4_sequence_res *res, |
@@ -611,13 +638,13 @@ static int nfs4_call_sync_sequence(struct nfs_client *clp, | |||
611 | int ret; | 638 | int ret; |
612 | struct rpc_task *task; | 639 | struct rpc_task *task; |
613 | struct nfs41_call_sync_data data = { | 640 | struct nfs41_call_sync_data data = { |
614 | .clp = clp, | 641 | .seq_server = server, |
615 | .seq_args = args, | 642 | .seq_args = args, |
616 | .seq_res = res, | 643 | .seq_res = res, |
617 | .cache_reply = cache_reply, | 644 | .cache_reply = cache_reply, |
618 | }; | 645 | }; |
619 | struct rpc_task_setup task_setup = { | 646 | struct rpc_task_setup task_setup = { |
620 | .rpc_client = clnt, | 647 | .rpc_client = server->client, |
621 | .rpc_message = msg, | 648 | .rpc_message = msg, |
622 | .callback_ops = &nfs41_call_sync_ops, | 649 | .callback_ops = &nfs41_call_sync_ops, |
623 | .callback_data = &data | 650 | .callback_data = &data |
@@ -642,10 +669,15 @@ int _nfs4_call_sync_session(struct nfs_server *server, | |||
642 | struct nfs4_sequence_res *res, | 669 | struct nfs4_sequence_res *res, |
643 | int cache_reply) | 670 | int cache_reply) |
644 | { | 671 | { |
645 | return nfs4_call_sync_sequence(server->nfs_client, server->client, | 672 | return nfs4_call_sync_sequence(server, msg, args, res, cache_reply, 0); |
646 | msg, args, res, cache_reply, 0); | ||
647 | } | 673 | } |
648 | 674 | ||
675 | #else | ||
676 | static int nfs4_sequence_done(struct rpc_task *task, | ||
677 | struct nfs4_sequence_res *res) | ||
678 | { | ||
679 | return 1; | ||
680 | } | ||
649 | #endif /* CONFIG_NFS_V4_1 */ | 681 | #endif /* CONFIG_NFS_V4_1 */ |
650 | 682 | ||
651 | int _nfs4_call_sync(struct nfs_server *server, | 683 | int _nfs4_call_sync(struct nfs_server *server, |
@@ -659,18 +691,9 @@ int _nfs4_call_sync(struct nfs_server *server, | |||
659 | } | 691 | } |
660 | 692 | ||
661 | #define nfs4_call_sync(server, msg, args, res, cache_reply) \ | 693 | #define nfs4_call_sync(server, msg, args, res, cache_reply) \ |
662 | (server)->nfs_client->cl_call_sync((server), (msg), &(args)->seq_args, \ | 694 | (server)->nfs_client->cl_mvops->call_sync((server), (msg), &(args)->seq_args, \ |
663 | &(res)->seq_res, (cache_reply)) | 695 | &(res)->seq_res, (cache_reply)) |
664 | 696 | ||
665 | static void nfs4_sequence_done(const struct nfs_server *server, | ||
666 | struct nfs4_sequence_res *res, int rpc_status) | ||
667 | { | ||
668 | #ifdef CONFIG_NFS_V4_1 | ||
669 | if (nfs4_has_session(server->nfs_client)) | ||
670 | nfs41_sequence_done(server->nfs_client, res, rpc_status); | ||
671 | #endif /* CONFIG_NFS_V4_1 */ | ||
672 | } | ||
673 | |||
674 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) | 697 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) |
675 | { | 698 | { |
676 | struct nfs_inode *nfsi = NFS_I(dir); | 699 | struct nfs_inode *nfsi = NFS_I(dir); |
@@ -745,19 +768,14 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | |||
745 | p->o_arg.server = server; | 768 | p->o_arg.server = server; |
746 | p->o_arg.bitmask = server->attr_bitmask; | 769 | p->o_arg.bitmask = server->attr_bitmask; |
747 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; | 770 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; |
748 | if (flags & O_EXCL) { | 771 | if (flags & O_CREAT) { |
749 | if (nfs4_has_persistent_session(server->nfs_client)) { | 772 | u32 *s; |
750 | /* GUARDED */ | 773 | |
751 | p->o_arg.u.attrs = &p->attrs; | ||
752 | memcpy(&p->attrs, attrs, sizeof(p->attrs)); | ||
753 | } else { /* EXCLUSIVE4_1 */ | ||
754 | u32 *s = (u32 *) p->o_arg.u.verifier.data; | ||
755 | s[0] = jiffies; | ||
756 | s[1] = current->pid; | ||
757 | } | ||
758 | } else if (flags & O_CREAT) { | ||
759 | p->o_arg.u.attrs = &p->attrs; | 774 | p->o_arg.u.attrs = &p->attrs; |
760 | memcpy(&p->attrs, attrs, sizeof(p->attrs)); | 775 | memcpy(&p->attrs, attrs, sizeof(p->attrs)); |
776 | s = (u32 *) p->o_arg.u.verifier.data; | ||
777 | s[0] = jiffies; | ||
778 | s[1] = current->pid; | ||
761 | } | 779 | } |
762 | p->c_arg.fh = &p->o_res.fh; | 780 | p->c_arg.fh = &p->o_res.fh; |
763 | p->c_arg.stateid = &p->o_res.stateid; | 781 | p->c_arg.stateid = &p->o_res.stateid; |
@@ -1255,8 +1273,6 @@ static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata) | |||
1255 | struct nfs4_opendata *data = calldata; | 1273 | struct nfs4_opendata *data = calldata; |
1256 | 1274 | ||
1257 | data->rpc_status = task->tk_status; | 1275 | data->rpc_status = task->tk_status; |
1258 | if (RPC_ASSASSINATED(task)) | ||
1259 | return; | ||
1260 | if (data->rpc_status == 0) { | 1276 | if (data->rpc_status == 0) { |
1261 | memcpy(data->o_res.stateid.data, data->c_res.stateid.data, | 1277 | memcpy(data->o_res.stateid.data, data->c_res.stateid.data, |
1262 | sizeof(data->o_res.stateid.data)); | 1278 | sizeof(data->o_res.stateid.data)); |
@@ -1356,13 +1372,13 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) | |||
1356 | } | 1372 | } |
1357 | /* Update sequence id. */ | 1373 | /* Update sequence id. */ |
1358 | data->o_arg.id = sp->so_owner_id.id; | 1374 | data->o_arg.id = sp->so_owner_id.id; |
1359 | data->o_arg.clientid = sp->so_client->cl_clientid; | 1375 | data->o_arg.clientid = sp->so_server->nfs_client->cl_clientid; |
1360 | if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) { | 1376 | if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) { |
1361 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; | 1377 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; |
1362 | nfs_copy_fh(&data->o_res.fh, data->o_arg.fh); | 1378 | nfs_copy_fh(&data->o_res.fh, data->o_arg.fh); |
1363 | } | 1379 | } |
1364 | data->timestamp = jiffies; | 1380 | data->timestamp = jiffies; |
1365 | if (nfs4_setup_sequence(data->o_arg.server->nfs_client, | 1381 | if (nfs4_setup_sequence(data->o_arg.server, |
1366 | &data->o_arg.seq_args, | 1382 | &data->o_arg.seq_args, |
1367 | &data->o_res.seq_res, 1, task)) | 1383 | &data->o_res.seq_res, 1, task)) |
1368 | return; | 1384 | return; |
@@ -1385,11 +1401,9 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata) | |||
1385 | 1401 | ||
1386 | data->rpc_status = task->tk_status; | 1402 | data->rpc_status = task->tk_status; |
1387 | 1403 | ||
1388 | nfs4_sequence_done(data->o_arg.server, &data->o_res.seq_res, | 1404 | if (!nfs4_sequence_done(task, &data->o_res.seq_res)) |
1389 | task->tk_status); | ||
1390 | |||
1391 | if (RPC_ASSASSINATED(task)) | ||
1392 | return; | 1405 | return; |
1406 | |||
1393 | if (task->tk_status == 0) { | 1407 | if (task->tk_status == 0) { |
1394 | switch (data->o_res.f_attr->mode & S_IFMT) { | 1408 | switch (data->o_res.f_attr->mode & S_IFMT) { |
1395 | case S_IFREG: | 1409 | case S_IFREG: |
@@ -1773,7 +1787,7 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | |||
1773 | if (nfs4_copy_delegation_stateid(&arg.stateid, inode)) { | 1787 | if (nfs4_copy_delegation_stateid(&arg.stateid, inode)) { |
1774 | /* Use that stateid */ | 1788 | /* Use that stateid */ |
1775 | } else if (state != NULL) { | 1789 | } else if (state != NULL) { |
1776 | nfs4_copy_stateid(&arg.stateid, state, current->files); | 1790 | nfs4_copy_stateid(&arg.stateid, state, current->files, current->tgid); |
1777 | } else | 1791 | } else |
1778 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); | 1792 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); |
1779 | 1793 | ||
@@ -1838,8 +1852,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1838 | struct nfs4_state *state = calldata->state; | 1852 | struct nfs4_state *state = calldata->state; |
1839 | struct nfs_server *server = NFS_SERVER(calldata->inode); | 1853 | struct nfs_server *server = NFS_SERVER(calldata->inode); |
1840 | 1854 | ||
1841 | nfs4_sequence_done(server, &calldata->res.seq_res, task->tk_status); | 1855 | if (!nfs4_sequence_done(task, &calldata->res.seq_res)) |
1842 | if (RPC_ASSASSINATED(task)) | ||
1843 | return; | 1856 | return; |
1844 | /* hmm. we are done with the inode, and in the process of freeing | 1857 | /* hmm. we are done with the inode, and in the process of freeing |
1845 | * the state_owner. we keep this around to process errors | 1858 | * the state_owner. we keep this around to process errors |
@@ -1903,7 +1916,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
1903 | 1916 | ||
1904 | nfs_fattr_init(calldata->res.fattr); | 1917 | nfs_fattr_init(calldata->res.fattr); |
1905 | calldata->timestamp = jiffies; | 1918 | calldata->timestamp = jiffies; |
1906 | if (nfs4_setup_sequence((NFS_SERVER(calldata->inode))->nfs_client, | 1919 | if (nfs4_setup_sequence(NFS_SERVER(calldata->inode), |
1907 | &calldata->arg.seq_args, &calldata->res.seq_res, | 1920 | &calldata->arg.seq_args, &calldata->res.seq_res, |
1908 | 1, task)) | 1921 | 1, task)) |
1909 | return; | 1922 | return; |
@@ -2648,7 +2661,8 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir) | |||
2648 | { | 2661 | { |
2649 | struct nfs_removeres *res = task->tk_msg.rpc_resp; | 2662 | struct nfs_removeres *res = task->tk_msg.rpc_resp; |
2650 | 2663 | ||
2651 | nfs4_sequence_done(res->server, &res->seq_res, task->tk_status); | 2664 | if (!nfs4_sequence_done(task, &res->seq_res)) |
2665 | return 0; | ||
2652 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) | 2666 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) |
2653 | return 0; | 2667 | return 0; |
2654 | update_changeattr(dir, &res->cinfo); | 2668 | update_changeattr(dir, &res->cinfo); |
@@ -3093,7 +3107,8 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) | |||
3093 | 3107 | ||
3094 | dprintk("--> %s\n", __func__); | 3108 | dprintk("--> %s\n", __func__); |
3095 | 3109 | ||
3096 | nfs4_sequence_done(server, &data->res.seq_res, task->tk_status); | 3110 | if (!nfs4_sequence_done(task, &data->res.seq_res)) |
3111 | return -EAGAIN; | ||
3097 | 3112 | ||
3098 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { | 3113 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { |
3099 | nfs_restart_rpc(task, server->nfs_client); | 3114 | nfs_restart_rpc(task, server->nfs_client); |
@@ -3116,8 +3131,8 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) | |||
3116 | { | 3131 | { |
3117 | struct inode *inode = data->inode; | 3132 | struct inode *inode = data->inode; |
3118 | 3133 | ||
3119 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, | 3134 | if (!nfs4_sequence_done(task, &data->res.seq_res)) |
3120 | task->tk_status); | 3135 | return -EAGAIN; |
3121 | 3136 | ||
3122 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { | 3137 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { |
3123 | nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); | 3138 | nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
@@ -3145,8 +3160,9 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) | |||
3145 | { | 3160 | { |
3146 | struct inode *inode = data->inode; | 3161 | struct inode *inode = data->inode; |
3147 | 3162 | ||
3148 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, | 3163 | if (!nfs4_sequence_done(task, &data->res.seq_res)) |
3149 | task->tk_status); | 3164 | return -EAGAIN; |
3165 | |||
3150 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { | 3166 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { |
3151 | nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); | 3167 | nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
3152 | return -EAGAIN; | 3168 | return -EAGAIN; |
@@ -3196,10 +3212,7 @@ static void nfs4_renew_done(struct rpc_task *task, void *calldata) | |||
3196 | nfs4_schedule_state_recovery(clp); | 3212 | nfs4_schedule_state_recovery(clp); |
3197 | return; | 3213 | return; |
3198 | } | 3214 | } |
3199 | spin_lock(&clp->cl_lock); | 3215 | do_renew_lease(clp, timestamp); |
3200 | if (time_before(clp->cl_last_renewal,timestamp)) | ||
3201 | clp->cl_last_renewal = timestamp; | ||
3202 | spin_unlock(&clp->cl_lock); | ||
3203 | } | 3216 | } |
3204 | 3217 | ||
3205 | static const struct rpc_call_ops nfs4_renew_ops = { | 3218 | static const struct rpc_call_ops nfs4_renew_ops = { |
@@ -3240,10 +3253,7 @@ int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred) | |||
3240 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); | 3253 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); |
3241 | if (status < 0) | 3254 | if (status < 0) |
3242 | return status; | 3255 | return status; |
3243 | spin_lock(&clp->cl_lock); | 3256 | do_renew_lease(clp, now); |
3244 | if (time_before(clp->cl_last_renewal,now)) | ||
3245 | clp->cl_last_renewal = now; | ||
3246 | spin_unlock(&clp->cl_lock); | ||
3247 | return 0; | 3257 | return 0; |
3248 | } | 3258 | } |
3249 | 3259 | ||
@@ -3464,9 +3474,11 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen | |||
3464 | } | 3474 | } |
3465 | 3475 | ||
3466 | static int | 3476 | static int |
3467 | _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs_client *clp, struct nfs4_state *state) | 3477 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state) |
3468 | { | 3478 | { |
3469 | if (!clp || task->tk_status >= 0) | 3479 | struct nfs_client *clp = server->nfs_client; |
3480 | |||
3481 | if (task->tk_status >= 0) | ||
3470 | return 0; | 3482 | return 0; |
3471 | switch(task->tk_status) { | 3483 | switch(task->tk_status) { |
3472 | case -NFS4ERR_ADMIN_REVOKED: | 3484 | case -NFS4ERR_ADMIN_REVOKED: |
@@ -3498,8 +3510,7 @@ _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
3498 | return -EAGAIN; | 3510 | return -EAGAIN; |
3499 | #endif /* CONFIG_NFS_V4_1 */ | 3511 | #endif /* CONFIG_NFS_V4_1 */ |
3500 | case -NFS4ERR_DELAY: | 3512 | case -NFS4ERR_DELAY: |
3501 | if (server) | 3513 | nfs_inc_server_stats(server, NFSIOS_DELAY); |
3502 | nfs_inc_server_stats(server, NFSIOS_DELAY); | ||
3503 | case -NFS4ERR_GRACE: | 3514 | case -NFS4ERR_GRACE: |
3504 | case -EKEYEXPIRED: | 3515 | case -EKEYEXPIRED: |
3505 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | 3516 | rpc_delay(task, NFS4_POLL_RETRY_MAX); |
@@ -3520,12 +3531,6 @@ do_state_recovery: | |||
3520 | return -EAGAIN; | 3531 | return -EAGAIN; |
3521 | } | 3532 | } |
3522 | 3533 | ||
3523 | static int | ||
3524 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state) | ||
3525 | { | ||
3526 | return _nfs4_async_handle_error(task, server, server->nfs_client, state); | ||
3527 | } | ||
3528 | |||
3529 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, | 3534 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, |
3530 | unsigned short port, struct rpc_cred *cred, | 3535 | unsigned short port, struct rpc_cred *cred, |
3531 | struct nfs4_setclientid_res *res) | 3536 | struct nfs4_setclientid_res *res) |
@@ -3641,8 +3646,8 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) | |||
3641 | { | 3646 | { |
3642 | struct nfs4_delegreturndata *data = calldata; | 3647 | struct nfs4_delegreturndata *data = calldata; |
3643 | 3648 | ||
3644 | nfs4_sequence_done(data->res.server, &data->res.seq_res, | 3649 | if (!nfs4_sequence_done(task, &data->res.seq_res)) |
3645 | task->tk_status); | 3650 | return; |
3646 | 3651 | ||
3647 | switch (task->tk_status) { | 3652 | switch (task->tk_status) { |
3648 | case -NFS4ERR_STALE_STATEID: | 3653 | case -NFS4ERR_STALE_STATEID: |
@@ -3672,7 +3677,7 @@ static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data) | |||
3672 | 3677 | ||
3673 | d_data = (struct nfs4_delegreturndata *)data; | 3678 | d_data = (struct nfs4_delegreturndata *)data; |
3674 | 3679 | ||
3675 | if (nfs4_setup_sequence(d_data->res.server->nfs_client, | 3680 | if (nfs4_setup_sequence(d_data->res.server, |
3676 | &d_data->args.seq_args, | 3681 | &d_data->args.seq_args, |
3677 | &d_data->res.seq_res, 1, task)) | 3682 | &d_data->res.seq_res, 1, task)) |
3678 | return; | 3683 | return; |
@@ -3892,9 +3897,7 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
3892 | { | 3897 | { |
3893 | struct nfs4_unlockdata *calldata = data; | 3898 | struct nfs4_unlockdata *calldata = data; |
3894 | 3899 | ||
3895 | nfs4_sequence_done(calldata->server, &calldata->res.seq_res, | 3900 | if (!nfs4_sequence_done(task, &calldata->res.seq_res)) |
3896 | task->tk_status); | ||
3897 | if (RPC_ASSASSINATED(task)) | ||
3898 | return; | 3901 | return; |
3899 | switch (task->tk_status) { | 3902 | switch (task->tk_status) { |
3900 | case 0: | 3903 | case 0: |
@@ -3927,7 +3930,7 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data) | |||
3927 | return; | 3930 | return; |
3928 | } | 3931 | } |
3929 | calldata->timestamp = jiffies; | 3932 | calldata->timestamp = jiffies; |
3930 | if (nfs4_setup_sequence(calldata->server->nfs_client, | 3933 | if (nfs4_setup_sequence(calldata->server, |
3931 | &calldata->arg.seq_args, | 3934 | &calldata->arg.seq_args, |
3932 | &calldata->res.seq_res, 1, task)) | 3935 | &calldata->res.seq_res, 1, task)) |
3933 | return; | 3936 | return; |
@@ -4082,7 +4085,8 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) | |||
4082 | } else | 4085 | } else |
4083 | data->arg.new_lock_owner = 0; | 4086 | data->arg.new_lock_owner = 0; |
4084 | data->timestamp = jiffies; | 4087 | data->timestamp = jiffies; |
4085 | if (nfs4_setup_sequence(data->server->nfs_client, &data->arg.seq_args, | 4088 | if (nfs4_setup_sequence(data->server, |
4089 | &data->arg.seq_args, | ||
4086 | &data->res.seq_res, 1, task)) | 4090 | &data->res.seq_res, 1, task)) |
4087 | return; | 4091 | return; |
4088 | rpc_call_start(task); | 4092 | rpc_call_start(task); |
@@ -4101,12 +4105,10 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata) | |||
4101 | 4105 | ||
4102 | dprintk("%s: begin!\n", __func__); | 4106 | dprintk("%s: begin!\n", __func__); |
4103 | 4107 | ||
4104 | nfs4_sequence_done(data->server, &data->res.seq_res, | 4108 | if (!nfs4_sequence_done(task, &data->res.seq_res)) |
4105 | task->tk_status); | 4109 | return; |
4106 | 4110 | ||
4107 | data->rpc_status = task->tk_status; | 4111 | data->rpc_status = task->tk_status; |
4108 | if (RPC_ASSASSINATED(task)) | ||
4109 | goto out; | ||
4110 | if (data->arg.new_lock_owner != 0) { | 4112 | if (data->arg.new_lock_owner != 0) { |
4111 | if (data->rpc_status == 0) | 4113 | if (data->rpc_status == 0) |
4112 | nfs_confirm_seqid(&data->lsp->ls_seqid, 0); | 4114 | nfs_confirm_seqid(&data->lsp->ls_seqid, 0); |
@@ -4424,6 +4426,34 @@ out: | |||
4424 | return err; | 4426 | return err; |
4425 | } | 4427 | } |
4426 | 4428 | ||
4429 | static void nfs4_release_lockowner_release(void *calldata) | ||
4430 | { | ||
4431 | kfree(calldata); | ||
4432 | } | ||
4433 | |||
4434 | const struct rpc_call_ops nfs4_release_lockowner_ops = { | ||
4435 | .rpc_release = nfs4_release_lockowner_release, | ||
4436 | }; | ||
4437 | |||
4438 | void nfs4_release_lockowner(const struct nfs4_lock_state *lsp) | ||
4439 | { | ||
4440 | struct nfs_server *server = lsp->ls_state->owner->so_server; | ||
4441 | struct nfs_release_lockowner_args *args; | ||
4442 | struct rpc_message msg = { | ||
4443 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RELEASE_LOCKOWNER], | ||
4444 | }; | ||
4445 | |||
4446 | if (server->nfs_client->cl_mvops->minor_version != 0) | ||
4447 | return; | ||
4448 | args = kmalloc(sizeof(*args), GFP_NOFS); | ||
4449 | if (!args) | ||
4450 | return; | ||
4451 | args->lock_owner.clientid = server->nfs_client->cl_clientid; | ||
4452 | args->lock_owner.id = lsp->ls_id.id; | ||
4453 | msg.rpc_argp = args; | ||
4454 | rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, args); | ||
4455 | } | ||
4456 | |||
4427 | #define XATTR_NAME_NFSV4_ACL "system.nfs4_acl" | 4457 | #define XATTR_NAME_NFSV4_ACL "system.nfs4_acl" |
4428 | 4458 | ||
4429 | int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf, | 4459 | int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf, |
@@ -4611,7 +4641,8 @@ static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata) | |||
4611 | (struct nfs4_get_lease_time_data *)calldata; | 4641 | (struct nfs4_get_lease_time_data *)calldata; |
4612 | 4642 | ||
4613 | dprintk("--> %s\n", __func__); | 4643 | dprintk("--> %s\n", __func__); |
4614 | nfs41_sequence_done(data->clp, &data->res->lr_seq_res, task->tk_status); | 4644 | if (!nfs41_sequence_done(task, &data->res->lr_seq_res)) |
4645 | return; | ||
4615 | switch (task->tk_status) { | 4646 | switch (task->tk_status) { |
4616 | case -NFS4ERR_DELAY: | 4647 | case -NFS4ERR_DELAY: |
4617 | case -NFS4ERR_GRACE: | 4648 | case -NFS4ERR_GRACE: |
@@ -4805,13 +4836,6 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) | |||
4805 | if (!session) | 4836 | if (!session) |
4806 | return NULL; | 4837 | return NULL; |
4807 | 4838 | ||
4808 | /* | ||
4809 | * The create session reply races with the server back | ||
4810 | * channel probe. Mark the client NFS_CS_SESSION_INITING | ||
4811 | * so that the client back channel can find the | ||
4812 | * nfs_client struct | ||
4813 | */ | ||
4814 | clp->cl_cons_state = NFS_CS_SESSION_INITING; | ||
4815 | init_completion(&session->complete); | 4839 | init_completion(&session->complete); |
4816 | 4840 | ||
4817 | tbl = &session->fc_slot_table; | 4841 | tbl = &session->fc_slot_table; |
@@ -4824,6 +4848,8 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) | |||
4824 | spin_lock_init(&tbl->slot_tbl_lock); | 4848 | spin_lock_init(&tbl->slot_tbl_lock); |
4825 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table"); | 4849 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table"); |
4826 | 4850 | ||
4851 | session->session_state = 1<<NFS4_SESSION_INITING; | ||
4852 | |||
4827 | session->clp = clp; | 4853 | session->clp = clp; |
4828 | return session; | 4854 | return session; |
4829 | } | 4855 | } |
@@ -5040,6 +5066,10 @@ int nfs4_init_session(struct nfs_server *server) | |||
5040 | if (!nfs4_has_session(clp)) | 5066 | if (!nfs4_has_session(clp)) |
5041 | return 0; | 5067 | return 0; |
5042 | 5068 | ||
5069 | session = clp->cl_session; | ||
5070 | if (!test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state)) | ||
5071 | return 0; | ||
5072 | |||
5043 | rsize = server->rsize; | 5073 | rsize = server->rsize; |
5044 | if (rsize == 0) | 5074 | if (rsize == 0) |
5045 | rsize = NFS_MAX_FILE_IO_SIZE; | 5075 | rsize = NFS_MAX_FILE_IO_SIZE; |
@@ -5047,7 +5077,6 @@ int nfs4_init_session(struct nfs_server *server) | |||
5047 | if (wsize == 0) | 5077 | if (wsize == 0) |
5048 | wsize = NFS_MAX_FILE_IO_SIZE; | 5078 | wsize = NFS_MAX_FILE_IO_SIZE; |
5049 | 5079 | ||
5050 | session = clp->cl_session; | ||
5051 | session->fc_attrs.max_rqst_sz = wsize + nfs41_maxwrite_overhead; | 5080 | session->fc_attrs.max_rqst_sz = wsize + nfs41_maxwrite_overhead; |
5052 | session->fc_attrs.max_resp_sz = rsize + nfs41_maxread_overhead; | 5081 | session->fc_attrs.max_resp_sz = rsize + nfs41_maxread_overhead; |
5053 | 5082 | ||
@@ -5060,69 +5089,70 @@ int nfs4_init_session(struct nfs_server *server) | |||
5060 | /* | 5089 | /* |
5061 | * Renew the cl_session lease. | 5090 | * Renew the cl_session lease. |
5062 | */ | 5091 | */ |
5063 | static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) | 5092 | struct nfs4_sequence_data { |
5064 | { | 5093 | struct nfs_client *clp; |
5065 | struct nfs4_sequence_args args; | 5094 | struct nfs4_sequence_args args; |
5066 | struct nfs4_sequence_res res; | 5095 | struct nfs4_sequence_res res; |
5067 | 5096 | }; | |
5068 | struct rpc_message msg = { | ||
5069 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE], | ||
5070 | .rpc_argp = &args, | ||
5071 | .rpc_resp = &res, | ||
5072 | .rpc_cred = cred, | ||
5073 | }; | ||
5074 | |||
5075 | args.sa_cache_this = 0; | ||
5076 | |||
5077 | return nfs4_call_sync_sequence(clp, clp->cl_rpcclient, &msg, &args, | ||
5078 | &res, args.sa_cache_this, 1); | ||
5079 | } | ||
5080 | 5097 | ||
5081 | static void nfs41_sequence_release(void *data) | 5098 | static void nfs41_sequence_release(void *data) |
5082 | { | 5099 | { |
5083 | struct nfs_client *clp = (struct nfs_client *)data; | 5100 | struct nfs4_sequence_data *calldata = data; |
5101 | struct nfs_client *clp = calldata->clp; | ||
5084 | 5102 | ||
5085 | if (atomic_read(&clp->cl_count) > 1) | 5103 | if (atomic_read(&clp->cl_count) > 1) |
5086 | nfs4_schedule_state_renewal(clp); | 5104 | nfs4_schedule_state_renewal(clp); |
5087 | nfs_put_client(clp); | 5105 | nfs_put_client(clp); |
5106 | kfree(calldata); | ||
5107 | } | ||
5108 | |||
5109 | static int nfs41_sequence_handle_errors(struct rpc_task *task, struct nfs_client *clp) | ||
5110 | { | ||
5111 | switch(task->tk_status) { | ||
5112 | case -NFS4ERR_DELAY: | ||
5113 | case -EKEYEXPIRED: | ||
5114 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | ||
5115 | return -EAGAIN; | ||
5116 | default: | ||
5117 | nfs4_schedule_state_recovery(clp); | ||
5118 | } | ||
5119 | return 0; | ||
5088 | } | 5120 | } |
5089 | 5121 | ||
5090 | static void nfs41_sequence_call_done(struct rpc_task *task, void *data) | 5122 | static void nfs41_sequence_call_done(struct rpc_task *task, void *data) |
5091 | { | 5123 | { |
5092 | struct nfs_client *clp = (struct nfs_client *)data; | 5124 | struct nfs4_sequence_data *calldata = data; |
5125 | struct nfs_client *clp = calldata->clp; | ||
5093 | 5126 | ||
5094 | nfs41_sequence_done(clp, task->tk_msg.rpc_resp, task->tk_status); | 5127 | if (!nfs41_sequence_done(task, task->tk_msg.rpc_resp)) |
5128 | return; | ||
5095 | 5129 | ||
5096 | if (task->tk_status < 0) { | 5130 | if (task->tk_status < 0) { |
5097 | dprintk("%s ERROR %d\n", __func__, task->tk_status); | 5131 | dprintk("%s ERROR %d\n", __func__, task->tk_status); |
5098 | if (atomic_read(&clp->cl_count) == 1) | 5132 | if (atomic_read(&clp->cl_count) == 1) |
5099 | goto out; | 5133 | goto out; |
5100 | 5134 | ||
5101 | if (_nfs4_async_handle_error(task, NULL, clp, NULL) | 5135 | if (nfs41_sequence_handle_errors(task, clp) == -EAGAIN) { |
5102 | == -EAGAIN) { | 5136 | rpc_restart_call_prepare(task); |
5103 | nfs_restart_rpc(task, clp); | ||
5104 | return; | 5137 | return; |
5105 | } | 5138 | } |
5106 | } | 5139 | } |
5107 | dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred); | 5140 | dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred); |
5108 | out: | 5141 | out: |
5109 | kfree(task->tk_msg.rpc_argp); | ||
5110 | kfree(task->tk_msg.rpc_resp); | ||
5111 | |||
5112 | dprintk("<-- %s\n", __func__); | 5142 | dprintk("<-- %s\n", __func__); |
5113 | } | 5143 | } |
5114 | 5144 | ||
5115 | static void nfs41_sequence_prepare(struct rpc_task *task, void *data) | 5145 | static void nfs41_sequence_prepare(struct rpc_task *task, void *data) |
5116 | { | 5146 | { |
5117 | struct nfs_client *clp; | 5147 | struct nfs4_sequence_data *calldata = data; |
5148 | struct nfs_client *clp = calldata->clp; | ||
5118 | struct nfs4_sequence_args *args; | 5149 | struct nfs4_sequence_args *args; |
5119 | struct nfs4_sequence_res *res; | 5150 | struct nfs4_sequence_res *res; |
5120 | 5151 | ||
5121 | clp = (struct nfs_client *)data; | ||
5122 | args = task->tk_msg.rpc_argp; | 5152 | args = task->tk_msg.rpc_argp; |
5123 | res = task->tk_msg.rpc_resp; | 5153 | res = task->tk_msg.rpc_resp; |
5124 | 5154 | ||
5125 | if (nfs4_setup_sequence(clp, args, res, 0, task)) | 5155 | if (nfs41_setup_sequence(clp->cl_session, args, res, 0, task)) |
5126 | return; | 5156 | return; |
5127 | rpc_call_start(task); | 5157 | rpc_call_start(task); |
5128 | } | 5158 | } |
@@ -5133,32 +5163,67 @@ static const struct rpc_call_ops nfs41_sequence_ops = { | |||
5133 | .rpc_release = nfs41_sequence_release, | 5163 | .rpc_release = nfs41_sequence_release, |
5134 | }; | 5164 | }; |
5135 | 5165 | ||
5136 | static int nfs41_proc_async_sequence(struct nfs_client *clp, | 5166 | static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) |
5137 | struct rpc_cred *cred) | ||
5138 | { | 5167 | { |
5139 | struct nfs4_sequence_args *args; | 5168 | struct nfs4_sequence_data *calldata; |
5140 | struct nfs4_sequence_res *res; | ||
5141 | struct rpc_message msg = { | 5169 | struct rpc_message msg = { |
5142 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE], | 5170 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE], |
5143 | .rpc_cred = cred, | 5171 | .rpc_cred = cred, |
5144 | }; | 5172 | }; |
5173 | struct rpc_task_setup task_setup_data = { | ||
5174 | .rpc_client = clp->cl_rpcclient, | ||
5175 | .rpc_message = &msg, | ||
5176 | .callback_ops = &nfs41_sequence_ops, | ||
5177 | .flags = RPC_TASK_ASYNC | RPC_TASK_SOFT, | ||
5178 | }; | ||
5145 | 5179 | ||
5146 | if (!atomic_inc_not_zero(&clp->cl_count)) | 5180 | if (!atomic_inc_not_zero(&clp->cl_count)) |
5147 | return -EIO; | 5181 | return ERR_PTR(-EIO); |
5148 | args = kzalloc(sizeof(*args), GFP_NOFS); | 5182 | calldata = kmalloc(sizeof(*calldata), GFP_NOFS); |
5149 | res = kzalloc(sizeof(*res), GFP_NOFS); | 5183 | if (calldata == NULL) { |
5150 | if (!args || !res) { | ||
5151 | kfree(args); | ||
5152 | kfree(res); | ||
5153 | nfs_put_client(clp); | 5184 | nfs_put_client(clp); |
5154 | return -ENOMEM; | 5185 | return ERR_PTR(-ENOMEM); |
5155 | } | 5186 | } |
5156 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | 5187 | calldata->res.sr_slotid = NFS4_MAX_SLOT_TABLE; |
5157 | msg.rpc_argp = args; | 5188 | msg.rpc_argp = &calldata->args; |
5158 | msg.rpc_resp = res; | 5189 | msg.rpc_resp = &calldata->res; |
5190 | calldata->clp = clp; | ||
5191 | task_setup_data.callback_data = calldata; | ||
5159 | 5192 | ||
5160 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, | 5193 | return rpc_run_task(&task_setup_data); |
5161 | &nfs41_sequence_ops, (void *)clp); | 5194 | } |
5195 | |||
5196 | static int nfs41_proc_async_sequence(struct nfs_client *clp, struct rpc_cred *cred) | ||
5197 | { | ||
5198 | struct rpc_task *task; | ||
5199 | int ret = 0; | ||
5200 | |||
5201 | task = _nfs41_proc_sequence(clp, cred); | ||
5202 | if (IS_ERR(task)) | ||
5203 | ret = PTR_ERR(task); | ||
5204 | else | ||
5205 | rpc_put_task(task); | ||
5206 | dprintk("<-- %s status=%d\n", __func__, ret); | ||
5207 | return ret; | ||
5208 | } | ||
5209 | |||
5210 | static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) | ||
5211 | { | ||
5212 | struct rpc_task *task; | ||
5213 | int ret; | ||
5214 | |||
5215 | task = _nfs41_proc_sequence(clp, cred); | ||
5216 | if (IS_ERR(task)) { | ||
5217 | ret = PTR_ERR(task); | ||
5218 | goto out; | ||
5219 | } | ||
5220 | ret = rpc_wait_for_completion_task(task); | ||
5221 | if (!ret) | ||
5222 | ret = task->tk_status; | ||
5223 | rpc_put_task(task); | ||
5224 | out: | ||
5225 | dprintk("<-- %s status=%d\n", __func__, ret); | ||
5226 | return ret; | ||
5162 | } | 5227 | } |
5163 | 5228 | ||
5164 | struct nfs4_reclaim_complete_data { | 5229 | struct nfs4_reclaim_complete_data { |
@@ -5172,13 +5237,31 @@ static void nfs4_reclaim_complete_prepare(struct rpc_task *task, void *data) | |||
5172 | struct nfs4_reclaim_complete_data *calldata = data; | 5237 | struct nfs4_reclaim_complete_data *calldata = data; |
5173 | 5238 | ||
5174 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | 5239 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); |
5175 | if (nfs4_setup_sequence(calldata->clp, &calldata->arg.seq_args, | 5240 | if (nfs41_setup_sequence(calldata->clp->cl_session, |
5241 | &calldata->arg.seq_args, | ||
5176 | &calldata->res.seq_res, 0, task)) | 5242 | &calldata->res.seq_res, 0, task)) |
5177 | return; | 5243 | return; |
5178 | 5244 | ||
5179 | rpc_call_start(task); | 5245 | rpc_call_start(task); |
5180 | } | 5246 | } |
5181 | 5247 | ||
5248 | static int nfs41_reclaim_complete_handle_errors(struct rpc_task *task, struct nfs_client *clp) | ||
5249 | { | ||
5250 | switch(task->tk_status) { | ||
5251 | case 0: | ||
5252 | case -NFS4ERR_COMPLETE_ALREADY: | ||
5253 | case -NFS4ERR_WRONG_CRED: /* What to do here? */ | ||
5254 | break; | ||
5255 | case -NFS4ERR_DELAY: | ||
5256 | case -EKEYEXPIRED: | ||
5257 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | ||
5258 | return -EAGAIN; | ||
5259 | default: | ||
5260 | nfs4_schedule_state_recovery(clp); | ||
5261 | } | ||
5262 | return 0; | ||
5263 | } | ||
5264 | |||
5182 | static void nfs4_reclaim_complete_done(struct rpc_task *task, void *data) | 5265 | static void nfs4_reclaim_complete_done(struct rpc_task *task, void *data) |
5183 | { | 5266 | { |
5184 | struct nfs4_reclaim_complete_data *calldata = data; | 5267 | struct nfs4_reclaim_complete_data *calldata = data; |
@@ -5186,32 +5269,13 @@ static void nfs4_reclaim_complete_done(struct rpc_task *task, void *data) | |||
5186 | struct nfs4_sequence_res *res = &calldata->res.seq_res; | 5269 | struct nfs4_sequence_res *res = &calldata->res.seq_res; |
5187 | 5270 | ||
5188 | dprintk("--> %s\n", __func__); | 5271 | dprintk("--> %s\n", __func__); |
5189 | nfs41_sequence_done(clp, res, task->tk_status); | 5272 | if (!nfs41_sequence_done(task, res)) |
5190 | switch (task->tk_status) { | 5273 | return; |
5191 | case 0: | ||
5192 | case -NFS4ERR_COMPLETE_ALREADY: | ||
5193 | break; | ||
5194 | case -NFS4ERR_BADSESSION: | ||
5195 | case -NFS4ERR_DEADSESSION: | ||
5196 | /* | ||
5197 | * Handle the session error, but do not retry the operation, as | ||
5198 | * we have no way of telling whether the clientid had to be | ||
5199 | * reset before we got our reply. If reset, a new wave of | ||
5200 | * reclaim operations will follow, containing their own reclaim | ||
5201 | * complete. We don't want our retry to get on the way of | ||
5202 | * recovery by incorrectly indicating to the server that we're | ||
5203 | * done reclaiming state since the process had to be restarted. | ||
5204 | */ | ||
5205 | _nfs4_async_handle_error(task, NULL, clp, NULL); | ||
5206 | break; | ||
5207 | default: | ||
5208 | if (_nfs4_async_handle_error( | ||
5209 | task, NULL, clp, NULL) == -EAGAIN) { | ||
5210 | rpc_restart_call_prepare(task); | ||
5211 | return; | ||
5212 | } | ||
5213 | } | ||
5214 | 5274 | ||
5275 | if (nfs41_reclaim_complete_handle_errors(task, clp) == -EAGAIN) { | ||
5276 | rpc_restart_call_prepare(task); | ||
5277 | return; | ||
5278 | } | ||
5215 | dprintk("<-- %s\n", __func__); | 5279 | dprintk("<-- %s\n", __func__); |
5216 | } | 5280 | } |
5217 | 5281 | ||
@@ -5325,28 +5389,30 @@ struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = { | |||
5325 | }; | 5389 | }; |
5326 | #endif | 5390 | #endif |
5327 | 5391 | ||
5328 | /* | 5392 | static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = { |
5329 | * Per minor version reboot and network partition recovery ops | 5393 | .minor_version = 0, |
5330 | */ | 5394 | .call_sync = _nfs4_call_sync, |
5331 | 5395 | .validate_stateid = nfs4_validate_delegation_stateid, | |
5332 | struct nfs4_state_recovery_ops *nfs4_reboot_recovery_ops[] = { | 5396 | .reboot_recovery_ops = &nfs40_reboot_recovery_ops, |
5333 | &nfs40_reboot_recovery_ops, | 5397 | .nograce_recovery_ops = &nfs40_nograce_recovery_ops, |
5334 | #if defined(CONFIG_NFS_V4_1) | 5398 | .state_renewal_ops = &nfs40_state_renewal_ops, |
5335 | &nfs41_reboot_recovery_ops, | ||
5336 | #endif | ||
5337 | }; | 5399 | }; |
5338 | 5400 | ||
5339 | struct nfs4_state_recovery_ops *nfs4_nograce_recovery_ops[] = { | ||
5340 | &nfs40_nograce_recovery_ops, | ||
5341 | #if defined(CONFIG_NFS_V4_1) | 5401 | #if defined(CONFIG_NFS_V4_1) |
5342 | &nfs41_nograce_recovery_ops, | 5402 | static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = { |
5343 | #endif | 5403 | .minor_version = 1, |
5404 | .call_sync = _nfs4_call_sync_session, | ||
5405 | .validate_stateid = nfs41_validate_delegation_stateid, | ||
5406 | .reboot_recovery_ops = &nfs41_reboot_recovery_ops, | ||
5407 | .nograce_recovery_ops = &nfs41_nograce_recovery_ops, | ||
5408 | .state_renewal_ops = &nfs41_state_renewal_ops, | ||
5344 | }; | 5409 | }; |
5410 | #endif | ||
5345 | 5411 | ||
5346 | struct nfs4_state_maintenance_ops *nfs4_state_renewal_ops[] = { | 5412 | const struct nfs4_minor_version_ops *nfs_v4_minor_ops[] = { |
5347 | &nfs40_state_renewal_ops, | 5413 | [0] = &nfs_v4_0_minor_ops, |
5348 | #if defined(CONFIG_NFS_V4_1) | 5414 | #if defined(CONFIG_NFS_V4_1) |
5349 | &nfs41_state_renewal_ops, | 5415 | [1] = &nfs_v4_1_minor_ops, |
5350 | #endif | 5416 | #endif |
5351 | }; | 5417 | }; |
5352 | 5418 | ||
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c index d87f10327b72..72b6c580af13 100644 --- a/fs/nfs/nfs4renewd.c +++ b/fs/nfs/nfs4renewd.c | |||
@@ -54,14 +54,14 @@ | |||
54 | void | 54 | void |
55 | nfs4_renew_state(struct work_struct *work) | 55 | nfs4_renew_state(struct work_struct *work) |
56 | { | 56 | { |
57 | struct nfs4_state_maintenance_ops *ops; | 57 | const struct nfs4_state_maintenance_ops *ops; |
58 | struct nfs_client *clp = | 58 | struct nfs_client *clp = |
59 | container_of(work, struct nfs_client, cl_renewd.work); | 59 | container_of(work, struct nfs_client, cl_renewd.work); |
60 | struct rpc_cred *cred; | 60 | struct rpc_cred *cred; |
61 | long lease; | 61 | long lease; |
62 | unsigned long last, now; | 62 | unsigned long last, now; |
63 | 63 | ||
64 | ops = nfs4_state_renewal_ops[clp->cl_minorversion]; | 64 | ops = clp->cl_mvops->state_renewal_ops; |
65 | dprintk("%s: start\n", __func__); | 65 | dprintk("%s: start\n", __func__); |
66 | /* Are there any active superblocks? */ | 66 | /* Are there any active superblocks? */ |
67 | if (list_empty(&clp->cl_superblocks)) | 67 | if (list_empty(&clp->cl_superblocks)) |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 34acf5926fdc..3e2f19b04c06 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -145,7 +145,9 @@ static void nfs4_end_drain_session(struct nfs_client *clp) | |||
145 | struct nfs4_session *ses = clp->cl_session; | 145 | struct nfs4_session *ses = clp->cl_session; |
146 | int max_slots; | 146 | int max_slots; |
147 | 147 | ||
148 | if (test_and_clear_bit(NFS4CLNT_SESSION_DRAINING, &clp->cl_state)) { | 148 | if (ses == NULL) |
149 | return; | ||
150 | if (test_and_clear_bit(NFS4_SESSION_DRAINING, &ses->session_state)) { | ||
149 | spin_lock(&ses->fc_slot_table.slot_tbl_lock); | 151 | spin_lock(&ses->fc_slot_table.slot_tbl_lock); |
150 | max_slots = ses->fc_slot_table.max_slots; | 152 | max_slots = ses->fc_slot_table.max_slots; |
151 | while (max_slots--) { | 153 | while (max_slots--) { |
@@ -167,7 +169,7 @@ static int nfs4_begin_drain_session(struct nfs_client *clp) | |||
167 | struct nfs4_slot_table *tbl = &ses->fc_slot_table; | 169 | struct nfs4_slot_table *tbl = &ses->fc_slot_table; |
168 | 170 | ||
169 | spin_lock(&tbl->slot_tbl_lock); | 171 | spin_lock(&tbl->slot_tbl_lock); |
170 | set_bit(NFS4CLNT_SESSION_DRAINING, &clp->cl_state); | 172 | set_bit(NFS4_SESSION_DRAINING, &ses->session_state); |
171 | if (tbl->highest_used_slotid != -1) { | 173 | if (tbl->highest_used_slotid != -1) { |
172 | INIT_COMPLETION(ses->complete); | 174 | INIT_COMPLETION(ses->complete); |
173 | spin_unlock(&tbl->slot_tbl_lock); | 175 | spin_unlock(&tbl->slot_tbl_lock); |
@@ -371,7 +373,6 @@ nfs4_alloc_state_owner(void) | |||
371 | return NULL; | 373 | return NULL; |
372 | spin_lock_init(&sp->so_lock); | 374 | spin_lock_init(&sp->so_lock); |
373 | INIT_LIST_HEAD(&sp->so_states); | 375 | INIT_LIST_HEAD(&sp->so_states); |
374 | INIT_LIST_HEAD(&sp->so_delegations); | ||
375 | rpc_init_wait_queue(&sp->so_sequence.wait, "Seqid_waitqueue"); | 376 | rpc_init_wait_queue(&sp->so_sequence.wait, "Seqid_waitqueue"); |
376 | sp->so_seqid.sequence = &sp->so_sequence; | 377 | sp->so_seqid.sequence = &sp->so_sequence; |
377 | spin_lock_init(&sp->so_sequence.lock); | 378 | spin_lock_init(&sp->so_sequence.lock); |
@@ -384,7 +385,7 @@ static void | |||
384 | nfs4_drop_state_owner(struct nfs4_state_owner *sp) | 385 | nfs4_drop_state_owner(struct nfs4_state_owner *sp) |
385 | { | 386 | { |
386 | if (!RB_EMPTY_NODE(&sp->so_client_node)) { | 387 | if (!RB_EMPTY_NODE(&sp->so_client_node)) { |
387 | struct nfs_client *clp = sp->so_client; | 388 | struct nfs_client *clp = sp->so_server->nfs_client; |
388 | 389 | ||
389 | spin_lock(&clp->cl_lock); | 390 | spin_lock(&clp->cl_lock); |
390 | rb_erase(&sp->so_client_node, &clp->cl_state_owners); | 391 | rb_erase(&sp->so_client_node, &clp->cl_state_owners); |
@@ -406,7 +407,6 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct | |||
406 | new = nfs4_alloc_state_owner(); | 407 | new = nfs4_alloc_state_owner(); |
407 | if (new == NULL) | 408 | if (new == NULL) |
408 | return NULL; | 409 | return NULL; |
409 | new->so_client = clp; | ||
410 | new->so_server = server; | 410 | new->so_server = server; |
411 | new->so_cred = cred; | 411 | new->so_cred = cred; |
412 | spin_lock(&clp->cl_lock); | 412 | spin_lock(&clp->cl_lock); |
@@ -423,7 +423,7 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct | |||
423 | 423 | ||
424 | void nfs4_put_state_owner(struct nfs4_state_owner *sp) | 424 | void nfs4_put_state_owner(struct nfs4_state_owner *sp) |
425 | { | 425 | { |
426 | struct nfs_client *clp = sp->so_client; | 426 | struct nfs_client *clp = sp->so_server->nfs_client; |
427 | struct rpc_cred *cred = sp->so_cred; | 427 | struct rpc_cred *cred = sp->so_cred; |
428 | 428 | ||
429 | if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock)) | 429 | if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock)) |
@@ -602,12 +602,21 @@ void nfs4_close_sync(struct path *path, struct nfs4_state *state, fmode_t fmode) | |||
602 | * that is compatible with current->files | 602 | * that is compatible with current->files |
603 | */ | 603 | */ |
604 | static struct nfs4_lock_state * | 604 | static struct nfs4_lock_state * |
605 | __nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) | 605 | __nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid, unsigned int type) |
606 | { | 606 | { |
607 | struct nfs4_lock_state *pos; | 607 | struct nfs4_lock_state *pos; |
608 | list_for_each_entry(pos, &state->lock_states, ls_locks) { | 608 | list_for_each_entry(pos, &state->lock_states, ls_locks) { |
609 | if (pos->ls_owner != fl_owner) | 609 | if (type != NFS4_ANY_LOCK_TYPE && pos->ls_owner.lo_type != type) |
610 | continue; | 610 | continue; |
611 | switch (pos->ls_owner.lo_type) { | ||
612 | case NFS4_POSIX_LOCK_TYPE: | ||
613 | if (pos->ls_owner.lo_u.posix_owner != fl_owner) | ||
614 | continue; | ||
615 | break; | ||
616 | case NFS4_FLOCK_LOCK_TYPE: | ||
617 | if (pos->ls_owner.lo_u.flock_owner != fl_pid) | ||
618 | continue; | ||
619 | } | ||
611 | atomic_inc(&pos->ls_count); | 620 | atomic_inc(&pos->ls_count); |
612 | return pos; | 621 | return pos; |
613 | } | 622 | } |
@@ -619,10 +628,10 @@ __nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) | |||
619 | * exists, return an uninitialized one. | 628 | * exists, return an uninitialized one. |
620 | * | 629 | * |
621 | */ | 630 | */ |
622 | static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) | 631 | static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid, unsigned int type) |
623 | { | 632 | { |
624 | struct nfs4_lock_state *lsp; | 633 | struct nfs4_lock_state *lsp; |
625 | struct nfs_client *clp = state->owner->so_client; | 634 | struct nfs_client *clp = state->owner->so_server->nfs_client; |
626 | 635 | ||
627 | lsp = kzalloc(sizeof(*lsp), GFP_NOFS); | 636 | lsp = kzalloc(sizeof(*lsp), GFP_NOFS); |
628 | if (lsp == NULL) | 637 | if (lsp == NULL) |
@@ -633,7 +642,18 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f | |||
633 | lsp->ls_seqid.sequence = &lsp->ls_sequence; | 642 | lsp->ls_seqid.sequence = &lsp->ls_sequence; |
634 | atomic_set(&lsp->ls_count, 1); | 643 | atomic_set(&lsp->ls_count, 1); |
635 | lsp->ls_state = state; | 644 | lsp->ls_state = state; |
636 | lsp->ls_owner = fl_owner; | 645 | lsp->ls_owner.lo_type = type; |
646 | switch (lsp->ls_owner.lo_type) { | ||
647 | case NFS4_FLOCK_LOCK_TYPE: | ||
648 | lsp->ls_owner.lo_u.flock_owner = fl_pid; | ||
649 | break; | ||
650 | case NFS4_POSIX_LOCK_TYPE: | ||
651 | lsp->ls_owner.lo_u.posix_owner = fl_owner; | ||
652 | break; | ||
653 | default: | ||
654 | kfree(lsp); | ||
655 | return NULL; | ||
656 | } | ||
637 | spin_lock(&clp->cl_lock); | 657 | spin_lock(&clp->cl_lock); |
638 | nfs_alloc_unique_id(&clp->cl_lockowner_id, &lsp->ls_id, 1, 64); | 658 | nfs_alloc_unique_id(&clp->cl_lockowner_id, &lsp->ls_id, 1, 64); |
639 | spin_unlock(&clp->cl_lock); | 659 | spin_unlock(&clp->cl_lock); |
@@ -643,7 +663,7 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f | |||
643 | 663 | ||
644 | static void nfs4_free_lock_state(struct nfs4_lock_state *lsp) | 664 | static void nfs4_free_lock_state(struct nfs4_lock_state *lsp) |
645 | { | 665 | { |
646 | struct nfs_client *clp = lsp->ls_state->owner->so_client; | 666 | struct nfs_client *clp = lsp->ls_state->owner->so_server->nfs_client; |
647 | 667 | ||
648 | spin_lock(&clp->cl_lock); | 668 | spin_lock(&clp->cl_lock); |
649 | nfs_free_unique_id(&clp->cl_lockowner_id, &lsp->ls_id); | 669 | nfs_free_unique_id(&clp->cl_lockowner_id, &lsp->ls_id); |
@@ -657,13 +677,13 @@ static void nfs4_free_lock_state(struct nfs4_lock_state *lsp) | |||
657 | * exists, return an uninitialized one. | 677 | * exists, return an uninitialized one. |
658 | * | 678 | * |
659 | */ | 679 | */ |
660 | static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner) | 680 | static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner, pid_t pid, unsigned int type) |
661 | { | 681 | { |
662 | struct nfs4_lock_state *lsp, *new = NULL; | 682 | struct nfs4_lock_state *lsp, *new = NULL; |
663 | 683 | ||
664 | for(;;) { | 684 | for(;;) { |
665 | spin_lock(&state->state_lock); | 685 | spin_lock(&state->state_lock); |
666 | lsp = __nfs4_find_lock_state(state, owner); | 686 | lsp = __nfs4_find_lock_state(state, owner, pid, type); |
667 | if (lsp != NULL) | 687 | if (lsp != NULL) |
668 | break; | 688 | break; |
669 | if (new != NULL) { | 689 | if (new != NULL) { |
@@ -674,7 +694,7 @@ static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_ | |||
674 | break; | 694 | break; |
675 | } | 695 | } |
676 | spin_unlock(&state->state_lock); | 696 | spin_unlock(&state->state_lock); |
677 | new = nfs4_alloc_lock_state(state, owner); | 697 | new = nfs4_alloc_lock_state(state, owner, pid, type); |
678 | if (new == NULL) | 698 | if (new == NULL) |
679 | return NULL; | 699 | return NULL; |
680 | } | 700 | } |
@@ -701,6 +721,8 @@ void nfs4_put_lock_state(struct nfs4_lock_state *lsp) | |||
701 | if (list_empty(&state->lock_states)) | 721 | if (list_empty(&state->lock_states)) |
702 | clear_bit(LK_STATE_IN_USE, &state->flags); | 722 | clear_bit(LK_STATE_IN_USE, &state->flags); |
703 | spin_unlock(&state->state_lock); | 723 | spin_unlock(&state->state_lock); |
724 | if (lsp->ls_flags & NFS_LOCK_INITIALIZED) | ||
725 | nfs4_release_lockowner(lsp); | ||
704 | nfs4_free_lock_state(lsp); | 726 | nfs4_free_lock_state(lsp); |
705 | } | 727 | } |
706 | 728 | ||
@@ -728,7 +750,12 @@ int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl) | |||
728 | 750 | ||
729 | if (fl->fl_ops != NULL) | 751 | if (fl->fl_ops != NULL) |
730 | return 0; | 752 | return 0; |
731 | lsp = nfs4_get_lock_state(state, fl->fl_owner); | 753 | if (fl->fl_flags & FL_POSIX) |
754 | lsp = nfs4_get_lock_state(state, fl->fl_owner, 0, NFS4_POSIX_LOCK_TYPE); | ||
755 | else if (fl->fl_flags & FL_FLOCK) | ||
756 | lsp = nfs4_get_lock_state(state, 0, fl->fl_pid, NFS4_FLOCK_LOCK_TYPE); | ||
757 | else | ||
758 | return -EINVAL; | ||
732 | if (lsp == NULL) | 759 | if (lsp == NULL) |
733 | return -ENOMEM; | 760 | return -ENOMEM; |
734 | fl->fl_u.nfs4_fl.owner = lsp; | 761 | fl->fl_u.nfs4_fl.owner = lsp; |
@@ -740,7 +767,7 @@ int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl) | |||
740 | * Byte-range lock aware utility to initialize the stateid of read/write | 767 | * Byte-range lock aware utility to initialize the stateid of read/write |
741 | * requests. | 768 | * requests. |
742 | */ | 769 | */ |
743 | void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner) | 770 | void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid) |
744 | { | 771 | { |
745 | struct nfs4_lock_state *lsp; | 772 | struct nfs4_lock_state *lsp; |
746 | int seq; | 773 | int seq; |
@@ -753,7 +780,7 @@ void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t f | |||
753 | return; | 780 | return; |
754 | 781 | ||
755 | spin_lock(&state->state_lock); | 782 | spin_lock(&state->state_lock); |
756 | lsp = __nfs4_find_lock_state(state, fl_owner); | 783 | lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid, NFS4_ANY_LOCK_TYPE); |
757 | if (lsp != NULL && (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) | 784 | if (lsp != NULL && (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) |
758 | memcpy(dst, &lsp->ls_stateid, sizeof(*dst)); | 785 | memcpy(dst, &lsp->ls_stateid, sizeof(*dst)); |
759 | spin_unlock(&state->state_lock); | 786 | spin_unlock(&state->state_lock); |
@@ -1041,11 +1068,11 @@ restart: | |||
1041 | case -NFS4ERR_BAD_STATEID: | 1068 | case -NFS4ERR_BAD_STATEID: |
1042 | case -NFS4ERR_RECLAIM_BAD: | 1069 | case -NFS4ERR_RECLAIM_BAD: |
1043 | case -NFS4ERR_RECLAIM_CONFLICT: | 1070 | case -NFS4ERR_RECLAIM_CONFLICT: |
1044 | nfs4_state_mark_reclaim_nograce(sp->so_client, state); | 1071 | nfs4_state_mark_reclaim_nograce(sp->so_server->nfs_client, state); |
1045 | break; | 1072 | break; |
1046 | case -NFS4ERR_EXPIRED: | 1073 | case -NFS4ERR_EXPIRED: |
1047 | case -NFS4ERR_NO_GRACE: | 1074 | case -NFS4ERR_NO_GRACE: |
1048 | nfs4_state_mark_reclaim_nograce(sp->so_client, state); | 1075 | nfs4_state_mark_reclaim_nograce(sp->so_server->nfs_client, state); |
1049 | case -NFS4ERR_STALE_CLIENTID: | 1076 | case -NFS4ERR_STALE_CLIENTID: |
1050 | case -NFS4ERR_BADSESSION: | 1077 | case -NFS4ERR_BADSESSION: |
1051 | case -NFS4ERR_BADSLOT: | 1078 | case -NFS4ERR_BADSLOT: |
@@ -1120,8 +1147,7 @@ static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp) | |||
1120 | if (!test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) | 1147 | if (!test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) |
1121 | return; | 1148 | return; |
1122 | 1149 | ||
1123 | nfs4_reclaim_complete(clp, | 1150 | nfs4_reclaim_complete(clp, clp->cl_mvops->reboot_recovery_ops); |
1124 | nfs4_reboot_recovery_ops[clp->cl_minorversion]); | ||
1125 | 1151 | ||
1126 | for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) { | 1152 | for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) { |
1127 | sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); | 1153 | sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); |
@@ -1211,8 +1237,8 @@ restart: | |||
1211 | static int nfs4_check_lease(struct nfs_client *clp) | 1237 | static int nfs4_check_lease(struct nfs_client *clp) |
1212 | { | 1238 | { |
1213 | struct rpc_cred *cred; | 1239 | struct rpc_cred *cred; |
1214 | struct nfs4_state_maintenance_ops *ops = | 1240 | const struct nfs4_state_maintenance_ops *ops = |
1215 | nfs4_state_renewal_ops[clp->cl_minorversion]; | 1241 | clp->cl_mvops->state_renewal_ops; |
1216 | int status = -NFS4ERR_EXPIRED; | 1242 | int status = -NFS4ERR_EXPIRED; |
1217 | 1243 | ||
1218 | /* Is the client already known to have an expired lease? */ | 1244 | /* Is the client already known to have an expired lease? */ |
@@ -1235,8 +1261,8 @@ out: | |||
1235 | static int nfs4_reclaim_lease(struct nfs_client *clp) | 1261 | static int nfs4_reclaim_lease(struct nfs_client *clp) |
1236 | { | 1262 | { |
1237 | struct rpc_cred *cred; | 1263 | struct rpc_cred *cred; |
1238 | struct nfs4_state_recovery_ops *ops = | 1264 | const struct nfs4_state_recovery_ops *ops = |
1239 | nfs4_reboot_recovery_ops[clp->cl_minorversion]; | 1265 | clp->cl_mvops->reboot_recovery_ops; |
1240 | int status = -ENOENT; | 1266 | int status = -ENOENT; |
1241 | 1267 | ||
1242 | cred = ops->get_clid_cred(clp); | 1268 | cred = ops->get_clid_cred(clp); |
@@ -1444,7 +1470,7 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1444 | /* First recover reboot state... */ | 1470 | /* First recover reboot state... */ |
1445 | if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) { | 1471 | if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) { |
1446 | status = nfs4_do_reclaim(clp, | 1472 | status = nfs4_do_reclaim(clp, |
1447 | nfs4_reboot_recovery_ops[clp->cl_minorversion]); | 1473 | clp->cl_mvops->reboot_recovery_ops); |
1448 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) || | 1474 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) || |
1449 | test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)) | 1475 | test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)) |
1450 | continue; | 1476 | continue; |
@@ -1458,7 +1484,7 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1458 | /* Now recover expired state... */ | 1484 | /* Now recover expired state... */ |
1459 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) { | 1485 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) { |
1460 | status = nfs4_do_reclaim(clp, | 1486 | status = nfs4_do_reclaim(clp, |
1461 | nfs4_nograce_recovery_ops[clp->cl_minorversion]); | 1487 | clp->cl_mvops->nograce_recovery_ops); |
1462 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) || | 1488 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) || |
1463 | test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) || | 1489 | test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) || |
1464 | test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) | 1490 | test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 65c8dae4b267..08ef91291132 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -202,14 +202,17 @@ static int nfs4_stat_to_errno(int); | |||
202 | #define encode_link_maxsz (op_encode_hdr_maxsz + \ | 202 | #define encode_link_maxsz (op_encode_hdr_maxsz + \ |
203 | nfs4_name_maxsz) | 203 | nfs4_name_maxsz) |
204 | #define decode_link_maxsz (op_decode_hdr_maxsz + decode_change_info_maxsz) | 204 | #define decode_link_maxsz (op_decode_hdr_maxsz + decode_change_info_maxsz) |
205 | #define encode_lockowner_maxsz (7) | ||
205 | #define encode_lock_maxsz (op_encode_hdr_maxsz + \ | 206 | #define encode_lock_maxsz (op_encode_hdr_maxsz + \ |
206 | 7 + \ | 207 | 7 + \ |
207 | 1 + encode_stateid_maxsz + 8) | 208 | 1 + encode_stateid_maxsz + 1 + \ |
209 | encode_lockowner_maxsz) | ||
208 | #define decode_lock_denied_maxsz \ | 210 | #define decode_lock_denied_maxsz \ |
209 | (8 + decode_lockowner_maxsz) | 211 | (8 + decode_lockowner_maxsz) |
210 | #define decode_lock_maxsz (op_decode_hdr_maxsz + \ | 212 | #define decode_lock_maxsz (op_decode_hdr_maxsz + \ |
211 | decode_lock_denied_maxsz) | 213 | decode_lock_denied_maxsz) |
212 | #define encode_lockt_maxsz (op_encode_hdr_maxsz + 12) | 214 | #define encode_lockt_maxsz (op_encode_hdr_maxsz + 5 + \ |
215 | encode_lockowner_maxsz) | ||
213 | #define decode_lockt_maxsz (op_decode_hdr_maxsz + \ | 216 | #define decode_lockt_maxsz (op_decode_hdr_maxsz + \ |
214 | decode_lock_denied_maxsz) | 217 | decode_lock_denied_maxsz) |
215 | #define encode_locku_maxsz (op_encode_hdr_maxsz + 3 + \ | 218 | #define encode_locku_maxsz (op_encode_hdr_maxsz + 3 + \ |
@@ -217,6 +220,11 @@ static int nfs4_stat_to_errno(int); | |||
217 | 4) | 220 | 4) |
218 | #define decode_locku_maxsz (op_decode_hdr_maxsz + \ | 221 | #define decode_locku_maxsz (op_decode_hdr_maxsz + \ |
219 | decode_stateid_maxsz) | 222 | decode_stateid_maxsz) |
223 | #define encode_release_lockowner_maxsz \ | ||
224 | (op_encode_hdr_maxsz + \ | ||
225 | encode_lockowner_maxsz) | ||
226 | #define decode_release_lockowner_maxsz \ | ||
227 | (op_decode_hdr_maxsz) | ||
220 | #define encode_access_maxsz (op_encode_hdr_maxsz + 1) | 228 | #define encode_access_maxsz (op_encode_hdr_maxsz + 1) |
221 | #define decode_access_maxsz (op_decode_hdr_maxsz + 2) | 229 | #define decode_access_maxsz (op_decode_hdr_maxsz + 2) |
222 | #define encode_symlink_maxsz (op_encode_hdr_maxsz + \ | 230 | #define encode_symlink_maxsz (op_encode_hdr_maxsz + \ |
@@ -471,6 +479,12 @@ static int nfs4_stat_to_errno(int); | |||
471 | decode_sequence_maxsz + \ | 479 | decode_sequence_maxsz + \ |
472 | decode_putfh_maxsz + \ | 480 | decode_putfh_maxsz + \ |
473 | decode_locku_maxsz) | 481 | decode_locku_maxsz) |
482 | #define NFS4_enc_release_lockowner_sz \ | ||
483 | (compound_encode_hdr_maxsz + \ | ||
484 | encode_lockowner_maxsz) | ||
485 | #define NFS4_dec_release_lockowner_sz \ | ||
486 | (compound_decode_hdr_maxsz + \ | ||
487 | decode_lockowner_maxsz) | ||
474 | #define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \ | 488 | #define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \ |
475 | encode_sequence_maxsz + \ | 489 | encode_sequence_maxsz + \ |
476 | encode_putfh_maxsz + \ | 490 | encode_putfh_maxsz + \ |
@@ -744,7 +758,7 @@ static void encode_compound_hdr(struct xdr_stream *xdr, | |||
744 | struct compound_hdr *hdr) | 758 | struct compound_hdr *hdr) |
745 | { | 759 | { |
746 | __be32 *p; | 760 | __be32 *p; |
747 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | 761 | struct rpc_auth *auth = req->rq_cred->cr_auth; |
748 | 762 | ||
749 | /* initialize running count of expected bytes in reply. | 763 | /* initialize running count of expected bytes in reply. |
750 | * NOTE: the replied tag SHOULD be the same is the one sent, | 764 | * NOTE: the replied tag SHOULD be the same is the one sent, |
@@ -1042,6 +1056,17 @@ static inline uint64_t nfs4_lock_length(struct file_lock *fl) | |||
1042 | return fl->fl_end - fl->fl_start + 1; | 1056 | return fl->fl_end - fl->fl_start + 1; |
1043 | } | 1057 | } |
1044 | 1058 | ||
1059 | static void encode_lockowner(struct xdr_stream *xdr, const struct nfs_lowner *lowner) | ||
1060 | { | ||
1061 | __be32 *p; | ||
1062 | |||
1063 | p = reserve_space(xdr, 28); | ||
1064 | p = xdr_encode_hyper(p, lowner->clientid); | ||
1065 | *p++ = cpu_to_be32(16); | ||
1066 | p = xdr_encode_opaque_fixed(p, "lock id:", 8); | ||
1067 | xdr_encode_hyper(p, lowner->id); | ||
1068 | } | ||
1069 | |||
1045 | /* | 1070 | /* |
1046 | * opcode,type,reclaim,offset,length,new_lock_owner = 32 | 1071 | * opcode,type,reclaim,offset,length,new_lock_owner = 32 |
1047 | * open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40 | 1072 | * open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40 |
@@ -1058,14 +1083,11 @@ static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args | |||
1058 | p = xdr_encode_hyper(p, nfs4_lock_length(args->fl)); | 1083 | p = xdr_encode_hyper(p, nfs4_lock_length(args->fl)); |
1059 | *p = cpu_to_be32(args->new_lock_owner); | 1084 | *p = cpu_to_be32(args->new_lock_owner); |
1060 | if (args->new_lock_owner){ | 1085 | if (args->new_lock_owner){ |
1061 | p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+32); | 1086 | p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4); |
1062 | *p++ = cpu_to_be32(args->open_seqid->sequence->counter); | 1087 | *p++ = cpu_to_be32(args->open_seqid->sequence->counter); |
1063 | p = xdr_encode_opaque_fixed(p, args->open_stateid->data, NFS4_STATEID_SIZE); | 1088 | p = xdr_encode_opaque_fixed(p, args->open_stateid->data, NFS4_STATEID_SIZE); |
1064 | *p++ = cpu_to_be32(args->lock_seqid->sequence->counter); | 1089 | *p++ = cpu_to_be32(args->lock_seqid->sequence->counter); |
1065 | p = xdr_encode_hyper(p, args->lock_owner.clientid); | 1090 | encode_lockowner(xdr, &args->lock_owner); |
1066 | *p++ = cpu_to_be32(16); | ||
1067 | p = xdr_encode_opaque_fixed(p, "lock id:", 8); | ||
1068 | xdr_encode_hyper(p, args->lock_owner.id); | ||
1069 | } | 1091 | } |
1070 | else { | 1092 | else { |
1071 | p = reserve_space(xdr, NFS4_STATEID_SIZE+4); | 1093 | p = reserve_space(xdr, NFS4_STATEID_SIZE+4); |
@@ -1080,15 +1102,12 @@ static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *ar | |||
1080 | { | 1102 | { |
1081 | __be32 *p; | 1103 | __be32 *p; |
1082 | 1104 | ||
1083 | p = reserve_space(xdr, 52); | 1105 | p = reserve_space(xdr, 24); |
1084 | *p++ = cpu_to_be32(OP_LOCKT); | 1106 | *p++ = cpu_to_be32(OP_LOCKT); |
1085 | *p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0)); | 1107 | *p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0)); |
1086 | p = xdr_encode_hyper(p, args->fl->fl_start); | 1108 | p = xdr_encode_hyper(p, args->fl->fl_start); |
1087 | p = xdr_encode_hyper(p, nfs4_lock_length(args->fl)); | 1109 | p = xdr_encode_hyper(p, nfs4_lock_length(args->fl)); |
1088 | p = xdr_encode_hyper(p, args->lock_owner.clientid); | 1110 | encode_lockowner(xdr, &args->lock_owner); |
1089 | *p++ = cpu_to_be32(16); | ||
1090 | p = xdr_encode_opaque_fixed(p, "lock id:", 8); | ||
1091 | xdr_encode_hyper(p, args->lock_owner.id); | ||
1092 | hdr->nops++; | 1111 | hdr->nops++; |
1093 | hdr->replen += decode_lockt_maxsz; | 1112 | hdr->replen += decode_lockt_maxsz; |
1094 | } | 1113 | } |
@@ -1108,6 +1127,17 @@ static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *ar | |||
1108 | hdr->replen += decode_locku_maxsz; | 1127 | hdr->replen += decode_locku_maxsz; |
1109 | } | 1128 | } |
1110 | 1129 | ||
1130 | static void encode_release_lockowner(struct xdr_stream *xdr, const struct nfs_lowner *lowner, struct compound_hdr *hdr) | ||
1131 | { | ||
1132 | __be32 *p; | ||
1133 | |||
1134 | p = reserve_space(xdr, 4); | ||
1135 | *p = cpu_to_be32(OP_RELEASE_LOCKOWNER); | ||
1136 | encode_lockowner(xdr, lowner); | ||
1137 | hdr->nops++; | ||
1138 | hdr->replen += decode_release_lockowner_maxsz; | ||
1139 | } | ||
1140 | |||
1111 | static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) | 1141 | static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) |
1112 | { | 1142 | { |
1113 | int len = name->len; | 1143 | int len = name->len; |
@@ -1172,7 +1202,7 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op | |||
1172 | break; | 1202 | break; |
1173 | default: | 1203 | default: |
1174 | clp = arg->server->nfs_client; | 1204 | clp = arg->server->nfs_client; |
1175 | if (clp->cl_minorversion > 0) { | 1205 | if (clp->cl_mvops->minor_version > 0) { |
1176 | if (nfs4_has_persistent_session(clp)) { | 1206 | if (nfs4_has_persistent_session(clp)) { |
1177 | *p = cpu_to_be32(NFS4_CREATE_GUARDED); | 1207 | *p = cpu_to_be32(NFS4_CREATE_GUARDED); |
1178 | encode_attrs(xdr, arg->u.attrs, arg->server); | 1208 | encode_attrs(xdr, arg->u.attrs, arg->server); |
@@ -1324,14 +1354,14 @@ static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
1324 | hdr->replen += decode_putrootfh_maxsz; | 1354 | hdr->replen += decode_putrootfh_maxsz; |
1325 | } | 1355 | } |
1326 | 1356 | ||
1327 | static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx) | 1357 | static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx, const struct nfs_lock_context *l_ctx) |
1328 | { | 1358 | { |
1329 | nfs4_stateid stateid; | 1359 | nfs4_stateid stateid; |
1330 | __be32 *p; | 1360 | __be32 *p; |
1331 | 1361 | ||
1332 | p = reserve_space(xdr, NFS4_STATEID_SIZE); | 1362 | p = reserve_space(xdr, NFS4_STATEID_SIZE); |
1333 | if (ctx->state != NULL) { | 1363 | if (ctx->state != NULL) { |
1334 | nfs4_copy_stateid(&stateid, ctx->state, ctx->lockowner); | 1364 | nfs4_copy_stateid(&stateid, ctx->state, l_ctx->lockowner, l_ctx->pid); |
1335 | xdr_encode_opaque_fixed(p, stateid.data, NFS4_STATEID_SIZE); | 1365 | xdr_encode_opaque_fixed(p, stateid.data, NFS4_STATEID_SIZE); |
1336 | } else | 1366 | } else |
1337 | xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE); | 1367 | xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE); |
@@ -1344,7 +1374,7 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, | |||
1344 | p = reserve_space(xdr, 4); | 1374 | p = reserve_space(xdr, 4); |
1345 | *p = cpu_to_be32(OP_READ); | 1375 | *p = cpu_to_be32(OP_READ); |
1346 | 1376 | ||
1347 | encode_stateid(xdr, args->context); | 1377 | encode_stateid(xdr, args->context, args->lock_context); |
1348 | 1378 | ||
1349 | p = reserve_space(xdr, 12); | 1379 | p = reserve_space(xdr, 12); |
1350 | p = xdr_encode_hyper(p, args->offset); | 1380 | p = xdr_encode_hyper(p, args->offset); |
@@ -1523,7 +1553,7 @@ static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *arg | |||
1523 | p = reserve_space(xdr, 4); | 1553 | p = reserve_space(xdr, 4); |
1524 | *p = cpu_to_be32(OP_WRITE); | 1554 | *p = cpu_to_be32(OP_WRITE); |
1525 | 1555 | ||
1526 | encode_stateid(xdr, args->context); | 1556 | encode_stateid(xdr, args->context, args->lock_context); |
1527 | 1557 | ||
1528 | p = reserve_space(xdr, 16); | 1558 | p = reserve_space(xdr, 16); |
1529 | p = xdr_encode_hyper(p, args->offset); | 1559 | p = xdr_encode_hyper(p, args->offset); |
@@ -1704,7 +1734,7 @@ static u32 nfs4_xdr_minorversion(const struct nfs4_sequence_args *args) | |||
1704 | { | 1734 | { |
1705 | #if defined(CONFIG_NFS_V4_1) | 1735 | #if defined(CONFIG_NFS_V4_1) |
1706 | if (args->sa_session) | 1736 | if (args->sa_session) |
1707 | return args->sa_session->clp->cl_minorversion; | 1737 | return args->sa_session->clp->cl_mvops->minor_version; |
1708 | #endif /* CONFIG_NFS_V4_1 */ | 1738 | #endif /* CONFIG_NFS_V4_1 */ |
1709 | return 0; | 1739 | return 0; |
1710 | } | 1740 | } |
@@ -2048,6 +2078,20 @@ static int nfs4_xdr_enc_locku(struct rpc_rqst *req, __be32 *p, struct nfs_locku_ | |||
2048 | return 0; | 2078 | return 0; |
2049 | } | 2079 | } |
2050 | 2080 | ||
2081 | static int nfs4_xdr_enc_release_lockowner(struct rpc_rqst *req, __be32 *p, struct nfs_release_lockowner_args *args) | ||
2082 | { | ||
2083 | struct xdr_stream xdr; | ||
2084 | struct compound_hdr hdr = { | ||
2085 | .minorversion = 0, | ||
2086 | }; | ||
2087 | |||
2088 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
2089 | encode_compound_hdr(&xdr, req, &hdr); | ||
2090 | encode_release_lockowner(&xdr, &args->lock_owner, &hdr); | ||
2091 | encode_nops(&hdr); | ||
2092 | return 0; | ||
2093 | } | ||
2094 | |||
2051 | /* | 2095 | /* |
2052 | * Encode a READLINK request | 2096 | * Encode a READLINK request |
2053 | */ | 2097 | */ |
@@ -2395,7 +2439,7 @@ static int nfs4_xdr_enc_exchange_id(struct rpc_rqst *req, uint32_t *p, | |||
2395 | { | 2439 | { |
2396 | struct xdr_stream xdr; | 2440 | struct xdr_stream xdr; |
2397 | struct compound_hdr hdr = { | 2441 | struct compound_hdr hdr = { |
2398 | .minorversion = args->client->cl_minorversion, | 2442 | .minorversion = args->client->cl_mvops->minor_version, |
2399 | }; | 2443 | }; |
2400 | 2444 | ||
2401 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2445 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
@@ -2413,7 +2457,7 @@ static int nfs4_xdr_enc_create_session(struct rpc_rqst *req, uint32_t *p, | |||
2413 | { | 2457 | { |
2414 | struct xdr_stream xdr; | 2458 | struct xdr_stream xdr; |
2415 | struct compound_hdr hdr = { | 2459 | struct compound_hdr hdr = { |
2416 | .minorversion = args->client->cl_minorversion, | 2460 | .minorversion = args->client->cl_mvops->minor_version, |
2417 | }; | 2461 | }; |
2418 | 2462 | ||
2419 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2463 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
@@ -2431,7 +2475,7 @@ static int nfs4_xdr_enc_destroy_session(struct rpc_rqst *req, uint32_t *p, | |||
2431 | { | 2475 | { |
2432 | struct xdr_stream xdr; | 2476 | struct xdr_stream xdr; |
2433 | struct compound_hdr hdr = { | 2477 | struct compound_hdr hdr = { |
2434 | .minorversion = session->clp->cl_minorversion, | 2478 | .minorversion = session->clp->cl_mvops->minor_version, |
2435 | }; | 2479 | }; |
2436 | 2480 | ||
2437 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2481 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
@@ -3973,6 +4017,11 @@ static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res) | |||
3973 | return status; | 4017 | return status; |
3974 | } | 4018 | } |
3975 | 4019 | ||
4020 | static int decode_release_lockowner(struct xdr_stream *xdr) | ||
4021 | { | ||
4022 | return decode_op_hdr(xdr, OP_RELEASE_LOCKOWNER); | ||
4023 | } | ||
4024 | |||
3976 | static int decode_lookup(struct xdr_stream *xdr) | 4025 | static int decode_lookup(struct xdr_stream *xdr) |
3977 | { | 4026 | { |
3978 | return decode_op_hdr(xdr, OP_LOOKUP); | 4027 | return decode_op_hdr(xdr, OP_LOOKUP); |
@@ -5259,6 +5308,19 @@ out: | |||
5259 | return status; | 5308 | return status; |
5260 | } | 5309 | } |
5261 | 5310 | ||
5311 | static int nfs4_xdr_dec_release_lockowner(struct rpc_rqst *rqstp, __be32 *p, void *dummy) | ||
5312 | { | ||
5313 | struct xdr_stream xdr; | ||
5314 | struct compound_hdr hdr; | ||
5315 | int status; | ||
5316 | |||
5317 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
5318 | status = decode_compound_hdr(&xdr, &hdr); | ||
5319 | if (!status) | ||
5320 | status = decode_release_lockowner(&xdr); | ||
5321 | return status; | ||
5322 | } | ||
5323 | |||
5262 | /* | 5324 | /* |
5263 | * Decode READLINK response | 5325 | * Decode READLINK response |
5264 | */ | 5326 | */ |
@@ -5866,6 +5928,7 @@ struct rpc_procinfo nfs4_procedures[] = { | |||
5866 | PROC(GETACL, enc_getacl, dec_getacl), | 5928 | PROC(GETACL, enc_getacl, dec_getacl), |
5867 | PROC(SETACL, enc_setacl, dec_setacl), | 5929 | PROC(SETACL, enc_setacl, dec_setacl), |
5868 | PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations), | 5930 | PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations), |
5931 | PROC(RELEASE_LOCKOWNER, enc_release_lockowner, dec_release_lockowner), | ||
5869 | #if defined(CONFIG_NFS_V4_1) | 5932 | #if defined(CONFIG_NFS_V4_1) |
5870 | PROC(EXCHANGE_ID, enc_exchange_id, dec_exchange_id), | 5933 | PROC(EXCHANGE_ID, enc_exchange_id, dec_exchange_id), |
5871 | PROC(CREATE_SESSION, enc_create_session, dec_create_session), | 5934 | PROC(CREATE_SESSION, enc_create_session, dec_create_session), |
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index a3654e57b589..919490232e17 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
@@ -79,6 +79,7 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode, | |||
79 | req->wb_pgbase = offset; | 79 | req->wb_pgbase = offset; |
80 | req->wb_bytes = count; | 80 | req->wb_bytes = count; |
81 | req->wb_context = get_nfs_open_context(ctx); | 81 | req->wb_context = get_nfs_open_context(ctx); |
82 | req->wb_lock_context = nfs_get_lock_context(ctx); | ||
82 | kref_init(&req->wb_kref); | 83 | kref_init(&req->wb_kref); |
83 | return req; | 84 | return req; |
84 | } | 85 | } |
@@ -141,11 +142,16 @@ void nfs_clear_request(struct nfs_page *req) | |||
141 | { | 142 | { |
142 | struct page *page = req->wb_page; | 143 | struct page *page = req->wb_page; |
143 | struct nfs_open_context *ctx = req->wb_context; | 144 | struct nfs_open_context *ctx = req->wb_context; |
145 | struct nfs_lock_context *l_ctx = req->wb_lock_context; | ||
144 | 146 | ||
145 | if (page != NULL) { | 147 | if (page != NULL) { |
146 | page_cache_release(page); | 148 | page_cache_release(page); |
147 | req->wb_page = NULL; | 149 | req->wb_page = NULL; |
148 | } | 150 | } |
151 | if (l_ctx != NULL) { | ||
152 | nfs_put_lock_context(l_ctx); | ||
153 | req->wb_lock_context = NULL; | ||
154 | } | ||
149 | if (ctx != NULL) { | 155 | if (ctx != NULL) { |
150 | put_nfs_open_context(ctx); | 156 | put_nfs_open_context(ctx); |
151 | req->wb_context = NULL; | 157 | req->wb_context = NULL; |
@@ -235,7 +241,7 @@ static int nfs_can_coalesce_requests(struct nfs_page *prev, | |||
235 | { | 241 | { |
236 | if (req->wb_context->cred != prev->wb_context->cred) | 242 | if (req->wb_context->cred != prev->wb_context->cred) |
237 | return 0; | 243 | return 0; |
238 | if (req->wb_context->lockowner != prev->wb_context->lockowner) | 244 | if (req->wb_lock_context->lockowner != prev->wb_lock_context->lockowner) |
239 | return 0; | 245 | return 0; |
240 | if (req->wb_context->state != prev->wb_context->state) | 246 | if (req->wb_context->state != prev->wb_context->state) |
241 | return 0; | 247 | return 0; |
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 6e2b06e6ca79..87adc2744246 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -190,6 +190,7 @@ static int nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | |||
190 | data->args.pages = data->pagevec; | 190 | data->args.pages = data->pagevec; |
191 | data->args.count = count; | 191 | data->args.count = count; |
192 | data->args.context = get_nfs_open_context(req->wb_context); | 192 | data->args.context = get_nfs_open_context(req->wb_context); |
193 | data->args.lock_context = req->wb_lock_context; | ||
193 | 194 | ||
194 | data->res.fattr = &data->fattr; | 195 | data->res.fattr = &data->fattr; |
195 | data->res.count = count; | 196 | data->res.count = count; |
@@ -410,7 +411,7 @@ void nfs_read_prepare(struct rpc_task *task, void *calldata) | |||
410 | { | 411 | { |
411 | struct nfs_read_data *data = calldata; | 412 | struct nfs_read_data *data = calldata; |
412 | 413 | ||
413 | if (nfs4_setup_sequence(NFS_SERVER(data->inode)->nfs_client, | 414 | if (nfs4_setup_sequence(NFS_SERVER(data->inode), |
414 | &data->args.seq_args, &data->res.seq_res, | 415 | &data->args.seq_args, &data->res.seq_res, |
415 | 0, task)) | 416 | 0, task)) |
416 | return; | 417 | return; |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index f9df16de4a56..f1ae39f6cb02 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -546,6 +546,9 @@ static void nfs_show_mountd_options(struct seq_file *m, struct nfs_server *nfss, | |||
546 | { | 546 | { |
547 | struct sockaddr *sap = (struct sockaddr *)&nfss->mountd_address; | 547 | struct sockaddr *sap = (struct sockaddr *)&nfss->mountd_address; |
548 | 548 | ||
549 | if (nfss->flags & NFS_MOUNT_LEGACY_INTERFACE) | ||
550 | return; | ||
551 | |||
549 | switch (sap->sa_family) { | 552 | switch (sap->sa_family) { |
550 | case AF_INET: { | 553 | case AF_INET: { |
551 | struct sockaddr_in *sin = (struct sockaddr_in *)sap; | 554 | struct sockaddr_in *sin = (struct sockaddr_in *)sap; |
@@ -1780,6 +1783,7 @@ static int nfs_validate_mount_data(void *options, | |||
1780 | * can deal with. | 1783 | * can deal with. |
1781 | */ | 1784 | */ |
1782 | args->flags = data->flags & NFS_MOUNT_FLAGMASK; | 1785 | args->flags = data->flags & NFS_MOUNT_FLAGMASK; |
1786 | args->flags |= NFS_MOUNT_LEGACY_INTERFACE; | ||
1783 | args->rsize = data->rsize; | 1787 | args->rsize = data->rsize; |
1784 | args->wsize = data->wsize; | 1788 | args->wsize = data->wsize; |
1785 | args->timeo = data->timeo; | 1789 | args->timeo = data->timeo; |
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index a2242af6a17d..2f84adaad427 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c | |||
@@ -110,7 +110,7 @@ void nfs_unlink_prepare(struct rpc_task *task, void *calldata) | |||
110 | struct nfs_unlinkdata *data = calldata; | 110 | struct nfs_unlinkdata *data = calldata; |
111 | struct nfs_server *server = NFS_SERVER(data->dir); | 111 | struct nfs_server *server = NFS_SERVER(data->dir); |
112 | 112 | ||
113 | if (nfs4_setup_sequence(server->nfs_client, &data->args.seq_args, | 113 | if (nfs4_setup_sequence(server, &data->args.seq_args, |
114 | &data->res.seq_res, 1, task)) | 114 | &data->res.seq_res, 1, task)) |
115 | return; | 115 | return; |
116 | rpc_call_start(task); | 116 | rpc_call_start(task); |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 9f81bdd91c55..874972d9427c 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -700,7 +700,9 @@ int nfs_flush_incompatible(struct file *file, struct page *page) | |||
700 | req = nfs_page_find_request(page); | 700 | req = nfs_page_find_request(page); |
701 | if (req == NULL) | 701 | if (req == NULL) |
702 | return 0; | 702 | return 0; |
703 | do_flush = req->wb_page != page || req->wb_context != ctx; | 703 | do_flush = req->wb_page != page || req->wb_context != ctx || |
704 | req->wb_lock_context->lockowner != current->files || | ||
705 | req->wb_lock_context->pid != current->tgid; | ||
704 | nfs_release_request(req); | 706 | nfs_release_request(req); |
705 | if (!do_flush) | 707 | if (!do_flush) |
706 | return 0; | 708 | return 0; |
@@ -824,6 +826,7 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
824 | data->args.pages = data->pagevec; | 826 | data->args.pages = data->pagevec; |
825 | data->args.count = count; | 827 | data->args.count = count; |
826 | data->args.context = get_nfs_open_context(req->wb_context); | 828 | data->args.context = get_nfs_open_context(req->wb_context); |
829 | data->args.lock_context = req->wb_lock_context; | ||
827 | data->args.stable = NFS_UNSTABLE; | 830 | data->args.stable = NFS_UNSTABLE; |
828 | if (how & FLUSH_STABLE) { | 831 | if (how & FLUSH_STABLE) { |
829 | data->args.stable = NFS_DATA_SYNC; | 832 | data->args.stable = NFS_DATA_SYNC; |
@@ -1047,9 +1050,9 @@ out: | |||
1047 | void nfs_write_prepare(struct rpc_task *task, void *calldata) | 1050 | void nfs_write_prepare(struct rpc_task *task, void *calldata) |
1048 | { | 1051 | { |
1049 | struct nfs_write_data *data = calldata; | 1052 | struct nfs_write_data *data = calldata; |
1050 | struct nfs_client *clp = (NFS_SERVER(data->inode))->nfs_client; | ||
1051 | 1053 | ||
1052 | if (nfs4_setup_sequence(clp, &data->args.seq_args, | 1054 | if (nfs4_setup_sequence(NFS_SERVER(data->inode), |
1055 | &data->args.seq_args, | ||
1053 | &data->res.seq_res, 1, task)) | 1056 | &data->res.seq_res, 1, task)) |
1054 | return; | 1057 | return; |
1055 | rpc_call_start(task); | 1058 | rpc_call_start(task); |
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 9b8299af3741..07e40c625972 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h | |||
@@ -523,6 +523,7 @@ enum { | |||
523 | NFSPROC4_CLNT_GETACL, | 523 | NFSPROC4_CLNT_GETACL, |
524 | NFSPROC4_CLNT_SETACL, | 524 | NFSPROC4_CLNT_SETACL, |
525 | NFSPROC4_CLNT_FS_LOCATIONS, | 525 | NFSPROC4_CLNT_FS_LOCATIONS, |
526 | NFSPROC4_CLNT_RELEASE_LOCKOWNER, | ||
526 | 527 | ||
527 | /* nfs41 */ | 528 | /* nfs41 */ |
528 | NFSPROC4_CLNT_EXCHANGE_ID, | 529 | NFSPROC4_CLNT_EXCHANGE_ID, |
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index bad4d121b16e..508f8cf6da37 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
@@ -72,13 +72,20 @@ struct nfs_access_entry { | |||
72 | int mask; | 72 | int mask; |
73 | }; | 73 | }; |
74 | 74 | ||
75 | struct nfs_lock_context { | ||
76 | atomic_t count; | ||
77 | struct list_head list; | ||
78 | struct nfs_open_context *open_context; | ||
79 | fl_owner_t lockowner; | ||
80 | pid_t pid; | ||
81 | }; | ||
82 | |||
75 | struct nfs4_state; | 83 | struct nfs4_state; |
76 | struct nfs_open_context { | 84 | struct nfs_open_context { |
77 | atomic_t count; | 85 | struct nfs_lock_context lock_context; |
78 | struct path path; | 86 | struct path path; |
79 | struct rpc_cred *cred; | 87 | struct rpc_cred *cred; |
80 | struct nfs4_state *state; | 88 | struct nfs4_state *state; |
81 | fl_owner_t lockowner; | ||
82 | fmode_t mode; | 89 | fmode_t mode; |
83 | 90 | ||
84 | unsigned long flags; | 91 | unsigned long flags; |
@@ -353,6 +360,8 @@ extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr); | |||
353 | extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx); | 360 | extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx); |
354 | extern void put_nfs_open_context(struct nfs_open_context *ctx); | 361 | extern void put_nfs_open_context(struct nfs_open_context *ctx); |
355 | extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, fmode_t mode); | 362 | extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, fmode_t mode); |
363 | extern struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx); | ||
364 | extern void nfs_put_lock_context(struct nfs_lock_context *l_ctx); | ||
356 | extern u64 nfs_compat_user_ino64(u64 fileid); | 365 | extern u64 nfs_compat_user_ino64(u64 fileid); |
357 | extern void nfs_fattr_init(struct nfs_fattr *fattr); | 366 | extern void nfs_fattr_init(struct nfs_fattr *fattr); |
358 | 367 | ||
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index d6e10a4c06e5..c82ee7cd6288 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h | |||
@@ -15,6 +15,7 @@ struct nlm_host; | |||
15 | struct nfs4_sequence_args; | 15 | struct nfs4_sequence_args; |
16 | struct nfs4_sequence_res; | 16 | struct nfs4_sequence_res; |
17 | struct nfs_server; | 17 | struct nfs_server; |
18 | struct nfs4_minor_version_ops; | ||
18 | 19 | ||
19 | /* | 20 | /* |
20 | * The nfs_client identifies our client state to the server. | 21 | * The nfs_client identifies our client state to the server. |
@@ -70,11 +71,7 @@ struct nfs_client { | |||
70 | */ | 71 | */ |
71 | char cl_ipaddr[48]; | 72 | char cl_ipaddr[48]; |
72 | unsigned char cl_id_uniquifier; | 73 | unsigned char cl_id_uniquifier; |
73 | int (* cl_call_sync)(struct nfs_server *server, | 74 | const struct nfs4_minor_version_ops *cl_mvops; |
74 | struct rpc_message *msg, | ||
75 | struct nfs4_sequence_args *args, | ||
76 | struct nfs4_sequence_res *res, | ||
77 | int cache_reply); | ||
78 | #endif /* CONFIG_NFS_V4 */ | 75 | #endif /* CONFIG_NFS_V4 */ |
79 | 76 | ||
80 | #ifdef CONFIG_NFS_V4_1 | 77 | #ifdef CONFIG_NFS_V4_1 |
diff --git a/include/linux/nfs_mount.h b/include/linux/nfs_mount.h index 4499016e6d0d..5d59ae861aa6 100644 --- a/include/linux/nfs_mount.h +++ b/include/linux/nfs_mount.h | |||
@@ -69,5 +69,6 @@ struct nfs_mount_data { | |||
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 | #define NFS_MOUNT_NORESVPORT 0x40000 |
72 | #define NFS_MOUNT_LEGACY_INTERFACE 0x80000 | ||
72 | 73 | ||
73 | #endif | 74 | #endif |
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index 3c60685d972b..f8b60e7f4c44 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h | |||
@@ -39,6 +39,7 @@ struct nfs_page { | |||
39 | struct list_head wb_list; /* Defines state of page: */ | 39 | struct list_head wb_list; /* Defines state of page: */ |
40 | struct page *wb_page; /* page to read in/write out */ | 40 | struct page *wb_page; /* page to read in/write out */ |
41 | struct nfs_open_context *wb_context; /* File state context info */ | 41 | struct nfs_open_context *wb_context; /* File state context info */ |
42 | struct nfs_lock_context *wb_lock_context; /* lock context info */ | ||
42 | atomic_t wb_complete; /* i/os we're waiting for */ | 43 | atomic_t wb_complete; /* i/os we're waiting for */ |
43 | pgoff_t wb_index; /* Offset >> PAGE_CACHE_SHIFT */ | 44 | pgoff_t wb_index; /* Offset >> PAGE_CACHE_SHIFT */ |
44 | unsigned int wb_offset, /* Offset & ~PAGE_CACHE_MASK */ | 45 | unsigned int wb_offset, /* Offset & ~PAGE_CACHE_MASK */ |
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 51914d7d6cc4..fc461926c412 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h | |||
@@ -196,8 +196,10 @@ struct nfs_openargs { | |||
196 | __u64 clientid; | 196 | __u64 clientid; |
197 | __u64 id; | 197 | __u64 id; |
198 | union { | 198 | union { |
199 | struct iattr * attrs; /* UNCHECKED, GUARDED */ | 199 | struct { |
200 | nfs4_verifier verifier; /* EXCLUSIVE */ | 200 | struct iattr * attrs; /* UNCHECKED, GUARDED */ |
201 | nfs4_verifier verifier; /* EXCLUSIVE */ | ||
202 | }; | ||
201 | nfs4_stateid delegation; /* CLAIM_DELEGATE_CUR */ | 203 | nfs4_stateid delegation; /* CLAIM_DELEGATE_CUR */ |
202 | fmode_t delegation_type; /* CLAIM_PREVIOUS */ | 204 | fmode_t delegation_type; /* CLAIM_PREVIOUS */ |
203 | } u; | 205 | } u; |
@@ -313,6 +315,10 @@ struct nfs_lockt_res { | |||
313 | struct nfs4_sequence_res seq_res; | 315 | struct nfs4_sequence_res seq_res; |
314 | }; | 316 | }; |
315 | 317 | ||
318 | struct nfs_release_lockowner_args { | ||
319 | struct nfs_lowner lock_owner; | ||
320 | }; | ||
321 | |||
316 | struct nfs4_delegreturnargs { | 322 | struct nfs4_delegreturnargs { |
317 | const struct nfs_fh *fhandle; | 323 | const struct nfs_fh *fhandle; |
318 | const nfs4_stateid *stateid; | 324 | const nfs4_stateid *stateid; |
@@ -332,6 +338,7 @@ struct nfs4_delegreturnres { | |||
332 | struct nfs_readargs { | 338 | struct nfs_readargs { |
333 | struct nfs_fh * fh; | 339 | struct nfs_fh * fh; |
334 | struct nfs_open_context *context; | 340 | struct nfs_open_context *context; |
341 | struct nfs_lock_context *lock_context; | ||
335 | __u64 offset; | 342 | __u64 offset; |
336 | __u32 count; | 343 | __u32 count; |
337 | unsigned int pgbase; | 344 | unsigned int pgbase; |
@@ -352,6 +359,7 @@ struct nfs_readres { | |||
352 | struct nfs_writeargs { | 359 | struct nfs_writeargs { |
353 | struct nfs_fh * fh; | 360 | struct nfs_fh * fh; |
354 | struct nfs_open_context *context; | 361 | struct nfs_open_context *context; |
362 | struct nfs_lock_context *lock_context; | ||
355 | __u64 offset; | 363 | __u64 offset; |
356 | __u32 count; | 364 | __u32 count; |
357 | enum nfs3_stable_how stable; | 365 | enum nfs3_stable_how stable; |
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index 87d7ec0bf779..5bbc447175dc 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h | |||
@@ -61,13 +61,7 @@ struct rpc_cred { | |||
61 | /* | 61 | /* |
62 | * Client authentication handle | 62 | * Client authentication handle |
63 | */ | 63 | */ |
64 | #define RPC_CREDCACHE_HASHBITS 4 | 64 | struct rpc_cred_cache; |
65 | #define RPC_CREDCACHE_NR (1 << RPC_CREDCACHE_HASHBITS) | ||
66 | struct rpc_cred_cache { | ||
67 | struct hlist_head hashtable[RPC_CREDCACHE_NR]; | ||
68 | spinlock_t lock; | ||
69 | }; | ||
70 | |||
71 | struct rpc_authops; | 65 | struct rpc_authops; |
72 | struct rpc_auth { | 66 | struct rpc_auth { |
73 | unsigned int au_cslack; /* call cred size estimate */ | 67 | unsigned int au_cslack; /* call cred size estimate */ |
@@ -112,7 +106,7 @@ struct rpc_credops { | |||
112 | void (*crdestroy)(struct rpc_cred *); | 106 | void (*crdestroy)(struct rpc_cred *); |
113 | 107 | ||
114 | int (*crmatch)(struct auth_cred *, struct rpc_cred *, int); | 108 | int (*crmatch)(struct auth_cred *, struct rpc_cred *, int); |
115 | void (*crbind)(struct rpc_task *, struct rpc_cred *, int); | 109 | struct rpc_cred * (*crbind)(struct rpc_task *, struct rpc_cred *, int); |
116 | __be32 * (*crmarshal)(struct rpc_task *, __be32 *); | 110 | __be32 * (*crmarshal)(struct rpc_task *, __be32 *); |
117 | int (*crrefresh)(struct rpc_task *); | 111 | int (*crrefresh)(struct rpc_task *); |
118 | __be32 * (*crvalidate)(struct rpc_task *, __be32 *); | 112 | __be32 * (*crvalidate)(struct rpc_task *, __be32 *); |
@@ -125,11 +119,12 @@ struct rpc_credops { | |||
125 | extern const struct rpc_authops authunix_ops; | 119 | extern const struct rpc_authops authunix_ops; |
126 | extern const struct rpc_authops authnull_ops; | 120 | extern const struct rpc_authops authnull_ops; |
127 | 121 | ||
128 | void __init rpc_init_authunix(void); | 122 | int __init rpc_init_authunix(void); |
129 | void __init rpc_init_generic_auth(void); | 123 | int __init rpc_init_generic_auth(void); |
130 | void __init rpcauth_init_module(void); | 124 | int __init rpcauth_init_module(void); |
131 | void __exit rpcauth_remove_module(void); | 125 | void __exit rpcauth_remove_module(void); |
132 | void __exit rpc_destroy_generic_auth(void); | 126 | void __exit rpc_destroy_generic_auth(void); |
127 | void rpc_destroy_authunix(void); | ||
133 | 128 | ||
134 | struct rpc_cred * rpc_lookup_cred(void); | 129 | struct rpc_cred * rpc_lookup_cred(void); |
135 | struct rpc_cred * rpc_lookup_machine_cred(void); | 130 | struct rpc_cred * rpc_lookup_machine_cred(void); |
@@ -140,10 +135,8 @@ void rpcauth_release(struct rpc_auth *); | |||
140 | struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int); | 135 | struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int); |
141 | void rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *); | 136 | void rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *); |
142 | struct rpc_cred * rpcauth_lookupcred(struct rpc_auth *, int); | 137 | struct rpc_cred * rpcauth_lookupcred(struct rpc_auth *, int); |
143 | void rpcauth_bindcred(struct rpc_task *, struct rpc_cred *, int); | 138 | struct rpc_cred * rpcauth_generic_bind_cred(struct rpc_task *, struct rpc_cred *, int); |
144 | void rpcauth_generic_bind_cred(struct rpc_task *, struct rpc_cred *, int); | ||
145 | void put_rpccred(struct rpc_cred *); | 139 | void put_rpccred(struct rpc_cred *); |
146 | void rpcauth_unbindcred(struct rpc_task *); | ||
147 | __be32 * rpcauth_marshcred(struct rpc_task *, __be32 *); | 140 | __be32 * rpcauth_marshcred(struct rpc_task *, __be32 *); |
148 | __be32 * rpcauth_checkverf(struct rpc_task *, __be32 *); | 141 | __be32 * rpcauth_checkverf(struct rpc_task *, __be32 *); |
149 | int rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, __be32 *data, void *obj); | 142 | int rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, __be32 *data, void *obj); |
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 8ed9642a5a76..569dc722a600 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h | |||
@@ -131,6 +131,7 @@ struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *, | |||
131 | struct rpc_clnt *rpc_clone_client(struct rpc_clnt *); | 131 | struct rpc_clnt *rpc_clone_client(struct rpc_clnt *); |
132 | void rpc_shutdown_client(struct rpc_clnt *); | 132 | void rpc_shutdown_client(struct rpc_clnt *); |
133 | void rpc_release_client(struct rpc_clnt *); | 133 | void rpc_release_client(struct rpc_clnt *); |
134 | void rpc_task_release_client(struct rpc_task *); | ||
134 | 135 | ||
135 | int rpcb_register(u32, u32, int, unsigned short); | 136 | int rpcb_register(u32, u32, int, unsigned short); |
136 | int rpcb_v4_register(const u32 program, const u32 version, | 137 | int rpcb_v4_register(const u32 program, const u32 version, |
@@ -148,8 +149,8 @@ int rpc_call_sync(struct rpc_clnt *clnt, | |||
148 | const struct rpc_message *msg, int flags); | 149 | const struct rpc_message *msg, int flags); |
149 | struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, | 150 | struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, |
150 | int flags); | 151 | int flags); |
151 | void rpc_restart_call_prepare(struct rpc_task *); | 152 | int rpc_restart_call_prepare(struct rpc_task *); |
152 | void rpc_restart_call(struct rpc_task *); | 153 | int rpc_restart_call(struct rpc_task *); |
153 | void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int); | 154 | void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int); |
154 | size_t rpc_max_payload(struct rpc_clnt *); | 155 | size_t rpc_max_payload(struct rpc_clnt *); |
155 | void rpc_force_rebind(struct rpc_clnt *); | 156 | void rpc_force_rebind(struct rpc_clnt *); |
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 7be4f3a6d246..88513fd8e208 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h | |||
@@ -213,6 +213,7 @@ struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req, | |||
213 | const struct rpc_call_ops *ops); | 213 | const struct rpc_call_ops *ops); |
214 | void rpc_put_task(struct rpc_task *); | 214 | void rpc_put_task(struct rpc_task *); |
215 | void rpc_exit_task(struct rpc_task *); | 215 | void rpc_exit_task(struct rpc_task *); |
216 | void rpc_exit(struct rpc_task *, int); | ||
216 | void rpc_release_calldata(const struct rpc_call_ops *, void *); | 217 | void rpc_release_calldata(const struct rpc_call_ops *, void *); |
217 | void rpc_killall_tasks(struct rpc_clnt *); | 218 | void rpc_killall_tasks(struct rpc_clnt *); |
218 | void rpc_execute(struct rpc_task *); | 219 | void rpc_execute(struct rpc_task *); |
@@ -241,12 +242,6 @@ void rpc_destroy_mempool(void); | |||
241 | extern struct workqueue_struct *rpciod_workqueue; | 242 | extern struct workqueue_struct *rpciod_workqueue; |
242 | void rpc_prepare_task(struct rpc_task *task); | 243 | void rpc_prepare_task(struct rpc_task *task); |
243 | 244 | ||
244 | static inline void rpc_exit(struct rpc_task *task, int status) | ||
245 | { | ||
246 | task->tk_status = status; | ||
247 | task->tk_action = rpc_exit_task; | ||
248 | } | ||
249 | |||
250 | static inline int rpc_wait_for_completion_task(struct rpc_task *task) | 245 | static inline int rpc_wait_for_completion_task(struct rpc_task *task) |
251 | { | 246 | { |
252 | return __rpc_wait_for_completion_task(task, NULL); | 247 | return __rpc_wait_for_completion_task(task, NULL); |
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index b51470302399..ff5a77b28c50 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h | |||
@@ -64,6 +64,7 @@ struct rpc_rqst { | |||
64 | * This is the private part | 64 | * This is the private part |
65 | */ | 65 | */ |
66 | struct rpc_task * rq_task; /* RPC task data */ | 66 | struct rpc_task * rq_task; /* RPC task data */ |
67 | struct rpc_cred * rq_cred; /* Bound cred */ | ||
67 | __be32 rq_xid; /* request XID */ | 68 | __be32 rq_xid; /* request XID */ |
68 | int rq_cong; /* has incremented xprt->cong */ | 69 | int rq_cong; /* has incremented xprt->cong */ |
69 | u32 rq_seqno; /* gss seq no. used on req. */ | 70 | u32 rq_seqno; /* gss seq no. used on req. */ |
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 8dc47f1d0001..880d0de3f50f 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c | |||
@@ -19,6 +19,15 @@ | |||
19 | # define RPCDBG_FACILITY RPCDBG_AUTH | 19 | # define RPCDBG_FACILITY RPCDBG_AUTH |
20 | #endif | 20 | #endif |
21 | 21 | ||
22 | #define RPC_CREDCACHE_DEFAULT_HASHBITS (4) | ||
23 | struct rpc_cred_cache { | ||
24 | struct hlist_head *hashtable; | ||
25 | unsigned int hashbits; | ||
26 | spinlock_t lock; | ||
27 | }; | ||
28 | |||
29 | static unsigned int auth_hashbits = RPC_CREDCACHE_DEFAULT_HASHBITS; | ||
30 | |||
22 | static DEFINE_SPINLOCK(rpc_authflavor_lock); | 31 | static DEFINE_SPINLOCK(rpc_authflavor_lock); |
23 | static const struct rpc_authops *auth_flavors[RPC_AUTH_MAXFLAVOR] = { | 32 | static const struct rpc_authops *auth_flavors[RPC_AUTH_MAXFLAVOR] = { |
24 | &authnull_ops, /* AUTH_NULL */ | 33 | &authnull_ops, /* AUTH_NULL */ |
@@ -29,6 +38,42 @@ static const struct rpc_authops *auth_flavors[RPC_AUTH_MAXFLAVOR] = { | |||
29 | static LIST_HEAD(cred_unused); | 38 | static LIST_HEAD(cred_unused); |
30 | static unsigned long number_cred_unused; | 39 | static unsigned long number_cred_unused; |
31 | 40 | ||
41 | #define MAX_HASHTABLE_BITS (10) | ||
42 | static int param_set_hashtbl_sz(const char *val, struct kernel_param *kp) | ||
43 | { | ||
44 | unsigned long num; | ||
45 | unsigned int nbits; | ||
46 | int ret; | ||
47 | |||
48 | if (!val) | ||
49 | goto out_inval; | ||
50 | ret = strict_strtoul(val, 0, &num); | ||
51 | if (ret == -EINVAL) | ||
52 | goto out_inval; | ||
53 | nbits = fls(num); | ||
54 | if (num > (1U << nbits)) | ||
55 | nbits++; | ||
56 | if (nbits > MAX_HASHTABLE_BITS || nbits < 2) | ||
57 | goto out_inval; | ||
58 | *(unsigned int *)kp->arg = nbits; | ||
59 | return 0; | ||
60 | out_inval: | ||
61 | return -EINVAL; | ||
62 | } | ||
63 | |||
64 | static int param_get_hashtbl_sz(char *buffer, struct kernel_param *kp) | ||
65 | { | ||
66 | unsigned int nbits; | ||
67 | |||
68 | nbits = *(unsigned int *)kp->arg; | ||
69 | return sprintf(buffer, "%u", 1U << nbits); | ||
70 | } | ||
71 | |||
72 | #define param_check_hashtbl_sz(name, p) __param_check(name, p, unsigned int); | ||
73 | |||
74 | module_param_named(auth_hashtable_size, auth_hashbits, hashtbl_sz, 0644); | ||
75 | MODULE_PARM_DESC(auth_hashtable_size, "RPC credential cache hashtable size"); | ||
76 | |||
32 | static u32 | 77 | static u32 |
33 | pseudoflavor_to_flavor(u32 flavor) { | 78 | pseudoflavor_to_flavor(u32 flavor) { |
34 | if (flavor >= RPC_AUTH_MAXFLAVOR) | 79 | if (flavor >= RPC_AUTH_MAXFLAVOR) |
@@ -145,16 +190,23 @@ int | |||
145 | rpcauth_init_credcache(struct rpc_auth *auth) | 190 | rpcauth_init_credcache(struct rpc_auth *auth) |
146 | { | 191 | { |
147 | struct rpc_cred_cache *new; | 192 | struct rpc_cred_cache *new; |
148 | int i; | 193 | unsigned int hashsize; |
149 | 194 | ||
150 | new = kmalloc(sizeof(*new), GFP_KERNEL); | 195 | new = kmalloc(sizeof(*new), GFP_KERNEL); |
151 | if (!new) | 196 | if (!new) |
152 | return -ENOMEM; | 197 | goto out_nocache; |
153 | for (i = 0; i < RPC_CREDCACHE_NR; i++) | 198 | new->hashbits = auth_hashbits; |
154 | INIT_HLIST_HEAD(&new->hashtable[i]); | 199 | hashsize = 1U << new->hashbits; |
200 | new->hashtable = kcalloc(hashsize, sizeof(new->hashtable[0]), GFP_KERNEL); | ||
201 | if (!new->hashtable) | ||
202 | goto out_nohashtbl; | ||
155 | spin_lock_init(&new->lock); | 203 | spin_lock_init(&new->lock); |
156 | auth->au_credcache = new; | 204 | auth->au_credcache = new; |
157 | return 0; | 205 | return 0; |
206 | out_nohashtbl: | ||
207 | kfree(new); | ||
208 | out_nocache: | ||
209 | return -ENOMEM; | ||
158 | } | 210 | } |
159 | EXPORT_SYMBOL_GPL(rpcauth_init_credcache); | 211 | EXPORT_SYMBOL_GPL(rpcauth_init_credcache); |
160 | 212 | ||
@@ -183,11 +235,12 @@ rpcauth_clear_credcache(struct rpc_cred_cache *cache) | |||
183 | LIST_HEAD(free); | 235 | LIST_HEAD(free); |
184 | struct hlist_head *head; | 236 | struct hlist_head *head; |
185 | struct rpc_cred *cred; | 237 | struct rpc_cred *cred; |
238 | unsigned int hashsize = 1U << cache->hashbits; | ||
186 | int i; | 239 | int i; |
187 | 240 | ||
188 | spin_lock(&rpc_credcache_lock); | 241 | spin_lock(&rpc_credcache_lock); |
189 | spin_lock(&cache->lock); | 242 | spin_lock(&cache->lock); |
190 | for (i = 0; i < RPC_CREDCACHE_NR; i++) { | 243 | for (i = 0; i < hashsize; i++) { |
191 | head = &cache->hashtable[i]; | 244 | head = &cache->hashtable[i]; |
192 | while (!hlist_empty(head)) { | 245 | while (!hlist_empty(head)) { |
193 | cred = hlist_entry(head->first, struct rpc_cred, cr_hash); | 246 | cred = hlist_entry(head->first, struct rpc_cred, cr_hash); |
@@ -216,6 +269,7 @@ rpcauth_destroy_credcache(struct rpc_auth *auth) | |||
216 | if (cache) { | 269 | if (cache) { |
217 | auth->au_credcache = NULL; | 270 | auth->au_credcache = NULL; |
218 | rpcauth_clear_credcache(cache); | 271 | rpcauth_clear_credcache(cache); |
272 | kfree(cache->hashtable); | ||
219 | kfree(cache); | 273 | kfree(cache); |
220 | } | 274 | } |
221 | } | 275 | } |
@@ -297,7 +351,7 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, | |||
297 | *entry, *new; | 351 | *entry, *new; |
298 | unsigned int nr; | 352 | unsigned int nr; |
299 | 353 | ||
300 | nr = hash_long(acred->uid, RPC_CREDCACHE_HASHBITS); | 354 | nr = hash_long(acred->uid, cache->hashbits); |
301 | 355 | ||
302 | rcu_read_lock(); | 356 | rcu_read_lock(); |
303 | hlist_for_each_entry_rcu(entry, pos, &cache->hashtable[nr], cr_hash) { | 357 | hlist_for_each_entry_rcu(entry, pos, &cache->hashtable[nr], cr_hash) { |
@@ -390,16 +444,16 @@ rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred, | |||
390 | } | 444 | } |
391 | EXPORT_SYMBOL_GPL(rpcauth_init_cred); | 445 | EXPORT_SYMBOL_GPL(rpcauth_init_cred); |
392 | 446 | ||
393 | void | 447 | struct rpc_cred * |
394 | rpcauth_generic_bind_cred(struct rpc_task *task, struct rpc_cred *cred, int lookupflags) | 448 | rpcauth_generic_bind_cred(struct rpc_task *task, struct rpc_cred *cred, int lookupflags) |
395 | { | 449 | { |
396 | task->tk_msg.rpc_cred = get_rpccred(cred); | ||
397 | dprintk("RPC: %5u holding %s cred %p\n", task->tk_pid, | 450 | dprintk("RPC: %5u holding %s cred %p\n", task->tk_pid, |
398 | cred->cr_auth->au_ops->au_name, cred); | 451 | cred->cr_auth->au_ops->au_name, cred); |
452 | return get_rpccred(cred); | ||
399 | } | 453 | } |
400 | EXPORT_SYMBOL_GPL(rpcauth_generic_bind_cred); | 454 | EXPORT_SYMBOL_GPL(rpcauth_generic_bind_cred); |
401 | 455 | ||
402 | static void | 456 | static struct rpc_cred * |
403 | rpcauth_bind_root_cred(struct rpc_task *task, int lookupflags) | 457 | rpcauth_bind_root_cred(struct rpc_task *task, int lookupflags) |
404 | { | 458 | { |
405 | struct rpc_auth *auth = task->tk_client->cl_auth; | 459 | struct rpc_auth *auth = task->tk_client->cl_auth; |
@@ -407,45 +461,43 @@ rpcauth_bind_root_cred(struct rpc_task *task, int lookupflags) | |||
407 | .uid = 0, | 461 | .uid = 0, |
408 | .gid = 0, | 462 | .gid = 0, |
409 | }; | 463 | }; |
410 | struct rpc_cred *ret; | ||
411 | 464 | ||
412 | dprintk("RPC: %5u looking up %s cred\n", | 465 | dprintk("RPC: %5u looking up %s cred\n", |
413 | task->tk_pid, task->tk_client->cl_auth->au_ops->au_name); | 466 | task->tk_pid, task->tk_client->cl_auth->au_ops->au_name); |
414 | ret = auth->au_ops->lookup_cred(auth, &acred, lookupflags); | 467 | return auth->au_ops->lookup_cred(auth, &acred, lookupflags); |
415 | if (!IS_ERR(ret)) | ||
416 | task->tk_msg.rpc_cred = ret; | ||
417 | else | ||
418 | task->tk_status = PTR_ERR(ret); | ||
419 | } | 468 | } |
420 | 469 | ||
421 | static void | 470 | static struct rpc_cred * |
422 | rpcauth_bind_new_cred(struct rpc_task *task, int lookupflags) | 471 | rpcauth_bind_new_cred(struct rpc_task *task, int lookupflags) |
423 | { | 472 | { |
424 | struct rpc_auth *auth = task->tk_client->cl_auth; | 473 | struct rpc_auth *auth = task->tk_client->cl_auth; |
425 | struct rpc_cred *ret; | ||
426 | 474 | ||
427 | dprintk("RPC: %5u looking up %s cred\n", | 475 | dprintk("RPC: %5u looking up %s cred\n", |
428 | task->tk_pid, auth->au_ops->au_name); | 476 | task->tk_pid, auth->au_ops->au_name); |
429 | ret = rpcauth_lookupcred(auth, lookupflags); | 477 | return rpcauth_lookupcred(auth, lookupflags); |
430 | if (!IS_ERR(ret)) | ||
431 | task->tk_msg.rpc_cred = ret; | ||
432 | else | ||
433 | task->tk_status = PTR_ERR(ret); | ||
434 | } | 478 | } |
435 | 479 | ||
436 | void | 480 | static int |
437 | rpcauth_bindcred(struct rpc_task *task, struct rpc_cred *cred, int flags) | 481 | rpcauth_bindcred(struct rpc_task *task, struct rpc_cred *cred, int flags) |
438 | { | 482 | { |
483 | struct rpc_rqst *req = task->tk_rqstp; | ||
484 | struct rpc_cred *new; | ||
439 | int lookupflags = 0; | 485 | int lookupflags = 0; |
440 | 486 | ||
441 | if (flags & RPC_TASK_ASYNC) | 487 | if (flags & RPC_TASK_ASYNC) |
442 | lookupflags |= RPCAUTH_LOOKUP_NEW; | 488 | lookupflags |= RPCAUTH_LOOKUP_NEW; |
443 | if (cred != NULL) | 489 | if (cred != NULL) |
444 | cred->cr_ops->crbind(task, cred, lookupflags); | 490 | new = cred->cr_ops->crbind(task, cred, lookupflags); |
445 | else if (flags & RPC_TASK_ROOTCREDS) | 491 | else if (flags & RPC_TASK_ROOTCREDS) |
446 | rpcauth_bind_root_cred(task, lookupflags); | 492 | new = rpcauth_bind_root_cred(task, lookupflags); |
447 | else | 493 | else |
448 | rpcauth_bind_new_cred(task, lookupflags); | 494 | new = rpcauth_bind_new_cred(task, lookupflags); |
495 | if (IS_ERR(new)) | ||
496 | return PTR_ERR(new); | ||
497 | if (req->rq_cred != NULL) | ||
498 | put_rpccred(req->rq_cred); | ||
499 | req->rq_cred = new; | ||
500 | return 0; | ||
449 | } | 501 | } |
450 | 502 | ||
451 | void | 503 | void |
@@ -484,22 +536,10 @@ out_nodestroy: | |||
484 | } | 536 | } |
485 | EXPORT_SYMBOL_GPL(put_rpccred); | 537 | EXPORT_SYMBOL_GPL(put_rpccred); |
486 | 538 | ||
487 | void | ||
488 | rpcauth_unbindcred(struct rpc_task *task) | ||
489 | { | ||
490 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | ||
491 | |||
492 | dprintk("RPC: %5u releasing %s cred %p\n", | ||
493 | task->tk_pid, cred->cr_auth->au_ops->au_name, cred); | ||
494 | |||
495 | put_rpccred(cred); | ||
496 | task->tk_msg.rpc_cred = NULL; | ||
497 | } | ||
498 | |||
499 | __be32 * | 539 | __be32 * |
500 | rpcauth_marshcred(struct rpc_task *task, __be32 *p) | 540 | rpcauth_marshcred(struct rpc_task *task, __be32 *p) |
501 | { | 541 | { |
502 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 542 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; |
503 | 543 | ||
504 | dprintk("RPC: %5u marshaling %s cred %p\n", | 544 | dprintk("RPC: %5u marshaling %s cred %p\n", |
505 | task->tk_pid, cred->cr_auth->au_ops->au_name, cred); | 545 | task->tk_pid, cred->cr_auth->au_ops->au_name, cred); |
@@ -510,7 +550,7 @@ rpcauth_marshcred(struct rpc_task *task, __be32 *p) | |||
510 | __be32 * | 550 | __be32 * |
511 | rpcauth_checkverf(struct rpc_task *task, __be32 *p) | 551 | rpcauth_checkverf(struct rpc_task *task, __be32 *p) |
512 | { | 552 | { |
513 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 553 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; |
514 | 554 | ||
515 | dprintk("RPC: %5u validating %s cred %p\n", | 555 | dprintk("RPC: %5u validating %s cred %p\n", |
516 | task->tk_pid, cred->cr_auth->au_ops->au_name, cred); | 556 | task->tk_pid, cred->cr_auth->au_ops->au_name, cred); |
@@ -522,7 +562,7 @@ int | |||
522 | rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, | 562 | rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, |
523 | __be32 *data, void *obj) | 563 | __be32 *data, void *obj) |
524 | { | 564 | { |
525 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 565 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; |
526 | 566 | ||
527 | dprintk("RPC: %5u using %s cred %p to wrap rpc data\n", | 567 | dprintk("RPC: %5u using %s cred %p to wrap rpc data\n", |
528 | task->tk_pid, cred->cr_ops->cr_name, cred); | 568 | task->tk_pid, cred->cr_ops->cr_name, cred); |
@@ -536,7 +576,7 @@ int | |||
536 | rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, | 576 | rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, |
537 | __be32 *data, void *obj) | 577 | __be32 *data, void *obj) |
538 | { | 578 | { |
539 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 579 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; |
540 | 580 | ||
541 | dprintk("RPC: %5u using %s cred %p to unwrap rpc data\n", | 581 | dprintk("RPC: %5u using %s cred %p to unwrap rpc data\n", |
542 | task->tk_pid, cred->cr_ops->cr_name, cred); | 582 | task->tk_pid, cred->cr_ops->cr_name, cred); |
@@ -550,13 +590,21 @@ rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, | |||
550 | int | 590 | int |
551 | rpcauth_refreshcred(struct rpc_task *task) | 591 | rpcauth_refreshcred(struct rpc_task *task) |
552 | { | 592 | { |
553 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 593 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; |
554 | int err; | 594 | int err; |
555 | 595 | ||
596 | cred = task->tk_rqstp->rq_cred; | ||
597 | if (cred == NULL) { | ||
598 | err = rpcauth_bindcred(task, task->tk_msg.rpc_cred, task->tk_flags); | ||
599 | if (err < 0) | ||
600 | goto out; | ||
601 | cred = task->tk_rqstp->rq_cred; | ||
602 | }; | ||
556 | dprintk("RPC: %5u refreshing %s cred %p\n", | 603 | dprintk("RPC: %5u refreshing %s cred %p\n", |
557 | task->tk_pid, cred->cr_auth->au_ops->au_name, cred); | 604 | task->tk_pid, cred->cr_auth->au_ops->au_name, cred); |
558 | 605 | ||
559 | err = cred->cr_ops->crrefresh(task); | 606 | err = cred->cr_ops->crrefresh(task); |
607 | out: | ||
560 | if (err < 0) | 608 | if (err < 0) |
561 | task->tk_status = err; | 609 | task->tk_status = err; |
562 | return err; | 610 | return err; |
@@ -565,7 +613,7 @@ rpcauth_refreshcred(struct rpc_task *task) | |||
565 | void | 613 | void |
566 | rpcauth_invalcred(struct rpc_task *task) | 614 | rpcauth_invalcred(struct rpc_task *task) |
567 | { | 615 | { |
568 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 616 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; |
569 | 617 | ||
570 | dprintk("RPC: %5u invalidating %s cred %p\n", | 618 | dprintk("RPC: %5u invalidating %s cred %p\n", |
571 | task->tk_pid, cred->cr_auth->au_ops->au_name, cred); | 619 | task->tk_pid, cred->cr_auth->au_ops->au_name, cred); |
@@ -576,7 +624,7 @@ rpcauth_invalcred(struct rpc_task *task) | |||
576 | int | 624 | int |
577 | rpcauth_uptodatecred(struct rpc_task *task) | 625 | rpcauth_uptodatecred(struct rpc_task *task) |
578 | { | 626 | { |
579 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 627 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; |
580 | 628 | ||
581 | return cred == NULL || | 629 | return cred == NULL || |
582 | test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0; | 630 | test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0; |
@@ -587,14 +635,27 @@ static struct shrinker rpc_cred_shrinker = { | |||
587 | .seeks = DEFAULT_SEEKS, | 635 | .seeks = DEFAULT_SEEKS, |
588 | }; | 636 | }; |
589 | 637 | ||
590 | void __init rpcauth_init_module(void) | 638 | int __init rpcauth_init_module(void) |
591 | { | 639 | { |
592 | rpc_init_authunix(); | 640 | int err; |
593 | rpc_init_generic_auth(); | 641 | |
642 | err = rpc_init_authunix(); | ||
643 | if (err < 0) | ||
644 | goto out1; | ||
645 | err = rpc_init_generic_auth(); | ||
646 | if (err < 0) | ||
647 | goto out2; | ||
594 | register_shrinker(&rpc_cred_shrinker); | 648 | register_shrinker(&rpc_cred_shrinker); |
649 | return 0; | ||
650 | out2: | ||
651 | rpc_destroy_authunix(); | ||
652 | out1: | ||
653 | return err; | ||
595 | } | 654 | } |
596 | 655 | ||
597 | void __exit rpcauth_remove_module(void) | 656 | void __exit rpcauth_remove_module(void) |
598 | { | 657 | { |
658 | rpc_destroy_authunix(); | ||
659 | rpc_destroy_generic_auth(); | ||
599 | unregister_shrinker(&rpc_cred_shrinker); | 660 | unregister_shrinker(&rpc_cred_shrinker); |
600 | } | 661 | } |
diff --git a/net/sunrpc/auth_generic.c b/net/sunrpc/auth_generic.c index 8f623b0f03dd..43162bb3b78f 100644 --- a/net/sunrpc/auth_generic.c +++ b/net/sunrpc/auth_generic.c | |||
@@ -27,7 +27,6 @@ struct generic_cred { | |||
27 | }; | 27 | }; |
28 | 28 | ||
29 | static struct rpc_auth generic_auth; | 29 | static struct rpc_auth generic_auth; |
30 | static struct rpc_cred_cache generic_cred_cache; | ||
31 | static const struct rpc_credops generic_credops; | 30 | static const struct rpc_credops generic_credops; |
32 | 31 | ||
33 | /* | 32 | /* |
@@ -55,18 +54,13 @@ struct rpc_cred *rpc_lookup_machine_cred(void) | |||
55 | } | 54 | } |
56 | EXPORT_SYMBOL_GPL(rpc_lookup_machine_cred); | 55 | EXPORT_SYMBOL_GPL(rpc_lookup_machine_cred); |
57 | 56 | ||
58 | static void | 57 | static struct rpc_cred *generic_bind_cred(struct rpc_task *task, |
59 | generic_bind_cred(struct rpc_task *task, struct rpc_cred *cred, int lookupflags) | 58 | struct rpc_cred *cred, int lookupflags) |
60 | { | 59 | { |
61 | struct rpc_auth *auth = task->tk_client->cl_auth; | 60 | struct rpc_auth *auth = task->tk_client->cl_auth; |
62 | struct auth_cred *acred = &container_of(cred, struct generic_cred, gc_base)->acred; | 61 | struct auth_cred *acred = &container_of(cred, struct generic_cred, gc_base)->acred; |
63 | struct rpc_cred *ret; | ||
64 | 62 | ||
65 | ret = auth->au_ops->lookup_cred(auth, acred, lookupflags); | 63 | return auth->au_ops->lookup_cred(auth, acred, lookupflags); |
66 | if (!IS_ERR(ret)) | ||
67 | task->tk_msg.rpc_cred = ret; | ||
68 | else | ||
69 | task->tk_status = PTR_ERR(ret); | ||
70 | } | 64 | } |
71 | 65 | ||
72 | /* | 66 | /* |
@@ -159,20 +153,16 @@ out_nomatch: | |||
159 | return 0; | 153 | return 0; |
160 | } | 154 | } |
161 | 155 | ||
162 | void __init rpc_init_generic_auth(void) | 156 | int __init rpc_init_generic_auth(void) |
163 | { | 157 | { |
164 | spin_lock_init(&generic_cred_cache.lock); | 158 | return rpcauth_init_credcache(&generic_auth); |
165 | } | 159 | } |
166 | 160 | ||
167 | void __exit rpc_destroy_generic_auth(void) | 161 | void __exit rpc_destroy_generic_auth(void) |
168 | { | 162 | { |
169 | rpcauth_clear_credcache(&generic_cred_cache); | 163 | rpcauth_destroy_credcache(&generic_auth); |
170 | } | 164 | } |
171 | 165 | ||
172 | static struct rpc_cred_cache generic_cred_cache = { | ||
173 | {{ NULL, },}, | ||
174 | }; | ||
175 | |||
176 | static const struct rpc_authops generic_auth_ops = { | 166 | static const struct rpc_authops generic_auth_ops = { |
177 | .owner = THIS_MODULE, | 167 | .owner = THIS_MODULE, |
178 | .au_name = "Generic", | 168 | .au_name = "Generic", |
@@ -183,7 +173,6 @@ static const struct rpc_authops generic_auth_ops = { | |||
183 | static struct rpc_auth generic_auth = { | 173 | static struct rpc_auth generic_auth = { |
184 | .au_ops = &generic_auth_ops, | 174 | .au_ops = &generic_auth_ops, |
185 | .au_count = ATOMIC_INIT(0), | 175 | .au_count = ATOMIC_INIT(0), |
186 | .au_credcache = &generic_cred_cache, | ||
187 | }; | 176 | }; |
188 | 177 | ||
189 | static const struct rpc_credops generic_credops = { | 178 | static const struct rpc_credops generic_credops = { |
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 8da2a0e68574..dcfc66bab2bb 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -373,7 +373,7 @@ gss_handle_downcall_result(struct gss_cred *gss_cred, struct gss_upcall_msg *gss | |||
373 | static void | 373 | static void |
374 | gss_upcall_callback(struct rpc_task *task) | 374 | gss_upcall_callback(struct rpc_task *task) |
375 | { | 375 | { |
376 | struct gss_cred *gss_cred = container_of(task->tk_msg.rpc_cred, | 376 | struct gss_cred *gss_cred = container_of(task->tk_rqstp->rq_cred, |
377 | struct gss_cred, gc_base); | 377 | struct gss_cred, gc_base); |
378 | struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall; | 378 | struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall; |
379 | struct inode *inode = &gss_msg->inode->vfs_inode; | 379 | struct inode *inode = &gss_msg->inode->vfs_inode; |
@@ -502,7 +502,7 @@ static void warn_gssd(void) | |||
502 | static inline int | 502 | static inline int |
503 | gss_refresh_upcall(struct rpc_task *task) | 503 | gss_refresh_upcall(struct rpc_task *task) |
504 | { | 504 | { |
505 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 505 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; |
506 | struct gss_auth *gss_auth = container_of(cred->cr_auth, | 506 | struct gss_auth *gss_auth = container_of(cred->cr_auth, |
507 | struct gss_auth, rpc_auth); | 507 | struct gss_auth, rpc_auth); |
508 | struct gss_cred *gss_cred = container_of(cred, | 508 | struct gss_cred *gss_cred = container_of(cred, |
@@ -928,6 +928,7 @@ gss_do_free_ctx(struct gss_cl_ctx *ctx) | |||
928 | { | 928 | { |
929 | dprintk("RPC: gss_free_ctx\n"); | 929 | dprintk("RPC: gss_free_ctx\n"); |
930 | 930 | ||
931 | gss_delete_sec_context(&ctx->gc_gss_ctx); | ||
931 | kfree(ctx->gc_wire_ctx.data); | 932 | kfree(ctx->gc_wire_ctx.data); |
932 | kfree(ctx); | 933 | kfree(ctx); |
933 | } | 934 | } |
@@ -942,13 +943,7 @@ gss_free_ctx_callback(struct rcu_head *head) | |||
942 | static void | 943 | static void |
943 | gss_free_ctx(struct gss_cl_ctx *ctx) | 944 | gss_free_ctx(struct gss_cl_ctx *ctx) |
944 | { | 945 | { |
945 | struct gss_ctx *gc_gss_ctx; | ||
946 | |||
947 | gc_gss_ctx = rcu_dereference(ctx->gc_gss_ctx); | ||
948 | rcu_assign_pointer(ctx->gc_gss_ctx, NULL); | ||
949 | call_rcu(&ctx->gc_rcu, gss_free_ctx_callback); | 946 | call_rcu(&ctx->gc_rcu, gss_free_ctx_callback); |
950 | if (gc_gss_ctx) | ||
951 | gss_delete_sec_context(&gc_gss_ctx); | ||
952 | } | 947 | } |
953 | 948 | ||
954 | static void | 949 | static void |
@@ -1064,12 +1059,12 @@ out: | |||
1064 | static __be32 * | 1059 | static __be32 * |
1065 | gss_marshal(struct rpc_task *task, __be32 *p) | 1060 | gss_marshal(struct rpc_task *task, __be32 *p) |
1066 | { | 1061 | { |
1067 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 1062 | struct rpc_rqst *req = task->tk_rqstp; |
1063 | struct rpc_cred *cred = req->rq_cred; | ||
1068 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, | 1064 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, |
1069 | gc_base); | 1065 | gc_base); |
1070 | struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); | 1066 | struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); |
1071 | __be32 *cred_len; | 1067 | __be32 *cred_len; |
1072 | struct rpc_rqst *req = task->tk_rqstp; | ||
1073 | u32 maj_stat = 0; | 1068 | u32 maj_stat = 0; |
1074 | struct xdr_netobj mic; | 1069 | struct xdr_netobj mic; |
1075 | struct kvec iov; | 1070 | struct kvec iov; |
@@ -1119,7 +1114,7 @@ out_put_ctx: | |||
1119 | 1114 | ||
1120 | static int gss_renew_cred(struct rpc_task *task) | 1115 | static int gss_renew_cred(struct rpc_task *task) |
1121 | { | 1116 | { |
1122 | struct rpc_cred *oldcred = task->tk_msg.rpc_cred; | 1117 | struct rpc_cred *oldcred = task->tk_rqstp->rq_cred; |
1123 | struct gss_cred *gss_cred = container_of(oldcred, | 1118 | struct gss_cred *gss_cred = container_of(oldcred, |
1124 | struct gss_cred, | 1119 | struct gss_cred, |
1125 | gc_base); | 1120 | gc_base); |
@@ -1133,7 +1128,7 @@ static int gss_renew_cred(struct rpc_task *task) | |||
1133 | new = gss_lookup_cred(auth, &acred, RPCAUTH_LOOKUP_NEW); | 1128 | new = gss_lookup_cred(auth, &acred, RPCAUTH_LOOKUP_NEW); |
1134 | if (IS_ERR(new)) | 1129 | if (IS_ERR(new)) |
1135 | return PTR_ERR(new); | 1130 | return PTR_ERR(new); |
1136 | task->tk_msg.rpc_cred = new; | 1131 | task->tk_rqstp->rq_cred = new; |
1137 | put_rpccred(oldcred); | 1132 | put_rpccred(oldcred); |
1138 | return 0; | 1133 | return 0; |
1139 | } | 1134 | } |
@@ -1161,7 +1156,7 @@ static int gss_cred_is_negative_entry(struct rpc_cred *cred) | |||
1161 | static int | 1156 | static int |
1162 | gss_refresh(struct rpc_task *task) | 1157 | gss_refresh(struct rpc_task *task) |
1163 | { | 1158 | { |
1164 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 1159 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; |
1165 | int ret = 0; | 1160 | int ret = 0; |
1166 | 1161 | ||
1167 | if (gss_cred_is_negative_entry(cred)) | 1162 | if (gss_cred_is_negative_entry(cred)) |
@@ -1172,7 +1167,7 @@ gss_refresh(struct rpc_task *task) | |||
1172 | ret = gss_renew_cred(task); | 1167 | ret = gss_renew_cred(task); |
1173 | if (ret < 0) | 1168 | if (ret < 0) |
1174 | goto out; | 1169 | goto out; |
1175 | cred = task->tk_msg.rpc_cred; | 1170 | cred = task->tk_rqstp->rq_cred; |
1176 | } | 1171 | } |
1177 | 1172 | ||
1178 | if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags)) | 1173 | if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags)) |
@@ -1191,7 +1186,7 @@ gss_refresh_null(struct rpc_task *task) | |||
1191 | static __be32 * | 1186 | static __be32 * |
1192 | gss_validate(struct rpc_task *task, __be32 *p) | 1187 | gss_validate(struct rpc_task *task, __be32 *p) |
1193 | { | 1188 | { |
1194 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 1189 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; |
1195 | struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); | 1190 | struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); |
1196 | __be32 seq; | 1191 | __be32 seq; |
1197 | struct kvec iov; | 1192 | struct kvec iov; |
@@ -1400,7 +1395,7 @@ static int | |||
1400 | gss_wrap_req(struct rpc_task *task, | 1395 | gss_wrap_req(struct rpc_task *task, |
1401 | kxdrproc_t encode, void *rqstp, __be32 *p, void *obj) | 1396 | kxdrproc_t encode, void *rqstp, __be32 *p, void *obj) |
1402 | { | 1397 | { |
1403 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 1398 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; |
1404 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, | 1399 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, |
1405 | gc_base); | 1400 | gc_base); |
1406 | struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); | 1401 | struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); |
@@ -1503,7 +1498,7 @@ static int | |||
1503 | gss_unwrap_resp(struct rpc_task *task, | 1498 | gss_unwrap_resp(struct rpc_task *task, |
1504 | kxdrproc_t decode, void *rqstp, __be32 *p, void *obj) | 1499 | kxdrproc_t decode, void *rqstp, __be32 *p, void *obj) |
1505 | { | 1500 | { |
1506 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 1501 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; |
1507 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, | 1502 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, |
1508 | gc_base); | 1503 | gc_base); |
1509 | struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); | 1504 | struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); |
diff --git a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c index 1db618f56ecb..a5c36c01707b 100644 --- a/net/sunrpc/auth_null.c +++ b/net/sunrpc/auth_null.c | |||
@@ -75,7 +75,7 @@ nul_marshal(struct rpc_task *task, __be32 *p) | |||
75 | static int | 75 | static int |
76 | nul_refresh(struct rpc_task *task) | 76 | nul_refresh(struct rpc_task *task) |
77 | { | 77 | { |
78 | set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_msg.rpc_cred->cr_flags); | 78 | set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_rqstp->rq_cred->cr_flags); |
79 | return 0; | 79 | return 0; |
80 | } | 80 | } |
81 | 81 | ||
diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c index aac2f8b4ee21..4cb70dc6e7ad 100644 --- a/net/sunrpc/auth_unix.c +++ b/net/sunrpc/auth_unix.c | |||
@@ -29,7 +29,6 @@ struct unx_cred { | |||
29 | #endif | 29 | #endif |
30 | 30 | ||
31 | static struct rpc_auth unix_auth; | 31 | static struct rpc_auth unix_auth; |
32 | static struct rpc_cred_cache unix_cred_cache; | ||
33 | static const struct rpc_credops unix_credops; | 32 | static const struct rpc_credops unix_credops; |
34 | 33 | ||
35 | static struct rpc_auth * | 34 | static struct rpc_auth * |
@@ -141,7 +140,7 @@ static __be32 * | |||
141 | unx_marshal(struct rpc_task *task, __be32 *p) | 140 | unx_marshal(struct rpc_task *task, __be32 *p) |
142 | { | 141 | { |
143 | struct rpc_clnt *clnt = task->tk_client; | 142 | struct rpc_clnt *clnt = task->tk_client; |
144 | struct unx_cred *cred = container_of(task->tk_msg.rpc_cred, struct unx_cred, uc_base); | 143 | struct unx_cred *cred = container_of(task->tk_rqstp->rq_cred, struct unx_cred, uc_base); |
145 | __be32 *base, *hold; | 144 | __be32 *base, *hold; |
146 | int i; | 145 | int i; |
147 | 146 | ||
@@ -174,7 +173,7 @@ unx_marshal(struct rpc_task *task, __be32 *p) | |||
174 | static int | 173 | static int |
175 | unx_refresh(struct rpc_task *task) | 174 | unx_refresh(struct rpc_task *task) |
176 | { | 175 | { |
177 | set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_msg.rpc_cred->cr_flags); | 176 | set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_rqstp->rq_cred->cr_flags); |
178 | return 0; | 177 | return 0; |
179 | } | 178 | } |
180 | 179 | ||
@@ -197,15 +196,20 @@ unx_validate(struct rpc_task *task, __be32 *p) | |||
197 | printk("RPC: giant verf size: %u\n", size); | 196 | printk("RPC: giant verf size: %u\n", size); |
198 | return NULL; | 197 | return NULL; |
199 | } | 198 | } |
200 | task->tk_msg.rpc_cred->cr_auth->au_rslack = (size >> 2) + 2; | 199 | task->tk_rqstp->rq_cred->cr_auth->au_rslack = (size >> 2) + 2; |
201 | p += (size >> 2); | 200 | p += (size >> 2); |
202 | 201 | ||
203 | return p; | 202 | return p; |
204 | } | 203 | } |
205 | 204 | ||
206 | void __init rpc_init_authunix(void) | 205 | int __init rpc_init_authunix(void) |
207 | { | 206 | { |
208 | spin_lock_init(&unix_cred_cache.lock); | 207 | return rpcauth_init_credcache(&unix_auth); |
208 | } | ||
209 | |||
210 | void rpc_destroy_authunix(void) | ||
211 | { | ||
212 | rpcauth_destroy_credcache(&unix_auth); | ||
209 | } | 213 | } |
210 | 214 | ||
211 | const struct rpc_authops authunix_ops = { | 215 | const struct rpc_authops authunix_ops = { |
@@ -219,17 +223,12 @@ const struct rpc_authops authunix_ops = { | |||
219 | }; | 223 | }; |
220 | 224 | ||
221 | static | 225 | static |
222 | struct rpc_cred_cache unix_cred_cache = { | ||
223 | }; | ||
224 | |||
225 | static | ||
226 | struct rpc_auth unix_auth = { | 226 | struct rpc_auth unix_auth = { |
227 | .au_cslack = UNX_WRITESLACK, | 227 | .au_cslack = UNX_WRITESLACK, |
228 | .au_rslack = 2, /* assume AUTH_NULL verf */ | 228 | .au_rslack = 2, /* assume AUTH_NULL verf */ |
229 | .au_ops = &authunix_ops, | 229 | .au_ops = &authunix_ops, |
230 | .au_flavor = RPC_AUTH_UNIX, | 230 | .au_flavor = RPC_AUTH_UNIX, |
231 | .au_count = ATOMIC_INIT(0), | 231 | .au_count = ATOMIC_INIT(0), |
232 | .au_credcache = &unix_cred_cache, | ||
233 | }; | 232 | }; |
234 | 233 | ||
235 | static | 234 | static |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 756fc324db9e..2388d83b68ff 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -414,6 +414,35 @@ out_no_clnt: | |||
414 | EXPORT_SYMBOL_GPL(rpc_clone_client); | 414 | EXPORT_SYMBOL_GPL(rpc_clone_client); |
415 | 415 | ||
416 | /* | 416 | /* |
417 | * Kill all tasks for the given client. | ||
418 | * XXX: kill their descendants as well? | ||
419 | */ | ||
420 | void rpc_killall_tasks(struct rpc_clnt *clnt) | ||
421 | { | ||
422 | struct rpc_task *rovr; | ||
423 | |||
424 | |||
425 | if (list_empty(&clnt->cl_tasks)) | ||
426 | return; | ||
427 | dprintk("RPC: killing all tasks for client %p\n", clnt); | ||
428 | /* | ||
429 | * Spin lock all_tasks to prevent changes... | ||
430 | */ | ||
431 | spin_lock(&clnt->cl_lock); | ||
432 | list_for_each_entry(rovr, &clnt->cl_tasks, tk_task) { | ||
433 | if (!RPC_IS_ACTIVATED(rovr)) | ||
434 | continue; | ||
435 | if (!(rovr->tk_flags & RPC_TASK_KILLED)) { | ||
436 | rovr->tk_flags |= RPC_TASK_KILLED; | ||
437 | rpc_exit(rovr, -EIO); | ||
438 | rpc_wake_up_queued_task(rovr->tk_waitqueue, rovr); | ||
439 | } | ||
440 | } | ||
441 | spin_unlock(&clnt->cl_lock); | ||
442 | } | ||
443 | EXPORT_SYMBOL_GPL(rpc_killall_tasks); | ||
444 | |||
445 | /* | ||
417 | * Properly shut down an RPC client, terminating all outstanding | 446 | * Properly shut down an RPC client, terminating all outstanding |
418 | * requests. | 447 | * requests. |
419 | */ | 448 | */ |
@@ -538,6 +567,49 @@ out: | |||
538 | } | 567 | } |
539 | EXPORT_SYMBOL_GPL(rpc_bind_new_program); | 568 | EXPORT_SYMBOL_GPL(rpc_bind_new_program); |
540 | 569 | ||
570 | void rpc_task_release_client(struct rpc_task *task) | ||
571 | { | ||
572 | struct rpc_clnt *clnt = task->tk_client; | ||
573 | |||
574 | if (clnt != NULL) { | ||
575 | /* Remove from client task list */ | ||
576 | spin_lock(&clnt->cl_lock); | ||
577 | list_del(&task->tk_task); | ||
578 | spin_unlock(&clnt->cl_lock); | ||
579 | task->tk_client = NULL; | ||
580 | |||
581 | rpc_release_client(clnt); | ||
582 | } | ||
583 | } | ||
584 | |||
585 | static | ||
586 | void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt) | ||
587 | { | ||
588 | if (clnt != NULL) { | ||
589 | rpc_task_release_client(task); | ||
590 | task->tk_client = clnt; | ||
591 | kref_get(&clnt->cl_kref); | ||
592 | if (clnt->cl_softrtry) | ||
593 | task->tk_flags |= RPC_TASK_SOFT; | ||
594 | /* Add to the client's list of all tasks */ | ||
595 | spin_lock(&clnt->cl_lock); | ||
596 | list_add_tail(&task->tk_task, &clnt->cl_tasks); | ||
597 | spin_unlock(&clnt->cl_lock); | ||
598 | } | ||
599 | } | ||
600 | |||
601 | static void | ||
602 | rpc_task_set_rpc_message(struct rpc_task *task, const struct rpc_message *msg) | ||
603 | { | ||
604 | if (msg != NULL) { | ||
605 | task->tk_msg.rpc_proc = msg->rpc_proc; | ||
606 | task->tk_msg.rpc_argp = msg->rpc_argp; | ||
607 | task->tk_msg.rpc_resp = msg->rpc_resp; | ||
608 | if (msg->rpc_cred != NULL) | ||
609 | task->tk_msg.rpc_cred = get_rpccred(msg->rpc_cred); | ||
610 | } | ||
611 | } | ||
612 | |||
541 | /* | 613 | /* |
542 | * Default callback for async RPC calls | 614 | * Default callback for async RPC calls |
543 | */ | 615 | */ |
@@ -562,6 +634,18 @@ struct rpc_task *rpc_run_task(const struct rpc_task_setup *task_setup_data) | |||
562 | if (IS_ERR(task)) | 634 | if (IS_ERR(task)) |
563 | goto out; | 635 | goto out; |
564 | 636 | ||
637 | rpc_task_set_client(task, task_setup_data->rpc_client); | ||
638 | rpc_task_set_rpc_message(task, task_setup_data->rpc_message); | ||
639 | |||
640 | if (task->tk_status != 0) { | ||
641 | int ret = task->tk_status; | ||
642 | rpc_put_task(task); | ||
643 | return ERR_PTR(ret); | ||
644 | } | ||
645 | |||
646 | if (task->tk_action == NULL) | ||
647 | rpc_call_start(task); | ||
648 | |||
565 | atomic_inc(&task->tk_count); | 649 | atomic_inc(&task->tk_count); |
566 | rpc_execute(task); | 650 | rpc_execute(task); |
567 | out: | 651 | out: |
@@ -756,12 +840,13 @@ EXPORT_SYMBOL_GPL(rpc_force_rebind); | |||
756 | * Restart an (async) RPC call from the call_prepare state. | 840 | * Restart an (async) RPC call from the call_prepare state. |
757 | * Usually called from within the exit handler. | 841 | * Usually called from within the exit handler. |
758 | */ | 842 | */ |
759 | void | 843 | int |
760 | rpc_restart_call_prepare(struct rpc_task *task) | 844 | rpc_restart_call_prepare(struct rpc_task *task) |
761 | { | 845 | { |
762 | if (RPC_ASSASSINATED(task)) | 846 | if (RPC_ASSASSINATED(task)) |
763 | return; | 847 | return 0; |
764 | task->tk_action = rpc_prepare_task; | 848 | task->tk_action = rpc_prepare_task; |
849 | return 1; | ||
765 | } | 850 | } |
766 | EXPORT_SYMBOL_GPL(rpc_restart_call_prepare); | 851 | EXPORT_SYMBOL_GPL(rpc_restart_call_prepare); |
767 | 852 | ||
@@ -769,13 +854,13 @@ EXPORT_SYMBOL_GPL(rpc_restart_call_prepare); | |||
769 | * Restart an (async) RPC call. Usually called from within the | 854 | * Restart an (async) RPC call. Usually called from within the |
770 | * exit handler. | 855 | * exit handler. |
771 | */ | 856 | */ |
772 | void | 857 | int |
773 | rpc_restart_call(struct rpc_task *task) | 858 | rpc_restart_call(struct rpc_task *task) |
774 | { | 859 | { |
775 | if (RPC_ASSASSINATED(task)) | 860 | if (RPC_ASSASSINATED(task)) |
776 | return; | 861 | return 0; |
777 | |||
778 | task->tk_action = call_start; | 862 | task->tk_action = call_start; |
863 | return 1; | ||
779 | } | 864 | } |
780 | EXPORT_SYMBOL_GPL(rpc_restart_call); | 865 | EXPORT_SYMBOL_GPL(rpc_restart_call); |
781 | 866 | ||
@@ -824,11 +909,6 @@ call_reserve(struct rpc_task *task) | |||
824 | { | 909 | { |
825 | dprint_status(task); | 910 | dprint_status(task); |
826 | 911 | ||
827 | if (!rpcauth_uptodatecred(task)) { | ||
828 | task->tk_action = call_refresh; | ||
829 | return; | ||
830 | } | ||
831 | |||
832 | task->tk_status = 0; | 912 | task->tk_status = 0; |
833 | task->tk_action = call_reserveresult; | 913 | task->tk_action = call_reserveresult; |
834 | xprt_reserve(task); | 914 | xprt_reserve(task); |
@@ -892,7 +972,7 @@ call_reserveresult(struct rpc_task *task) | |||
892 | static void | 972 | static void |
893 | call_allocate(struct rpc_task *task) | 973 | call_allocate(struct rpc_task *task) |
894 | { | 974 | { |
895 | unsigned int slack = task->tk_msg.rpc_cred->cr_auth->au_cslack; | 975 | unsigned int slack = task->tk_client->cl_auth->au_cslack; |
896 | struct rpc_rqst *req = task->tk_rqstp; | 976 | struct rpc_rqst *req = task->tk_rqstp; |
897 | struct rpc_xprt *xprt = task->tk_xprt; | 977 | struct rpc_xprt *xprt = task->tk_xprt; |
898 | struct rpc_procinfo *proc = task->tk_msg.rpc_proc; | 978 | struct rpc_procinfo *proc = task->tk_msg.rpc_proc; |
@@ -900,7 +980,7 @@ call_allocate(struct rpc_task *task) | |||
900 | dprint_status(task); | 980 | dprint_status(task); |
901 | 981 | ||
902 | task->tk_status = 0; | 982 | task->tk_status = 0; |
903 | task->tk_action = call_bind; | 983 | task->tk_action = call_refresh; |
904 | 984 | ||
905 | if (req->rq_buffer) | 985 | if (req->rq_buffer) |
906 | return; | 986 | return; |
@@ -937,6 +1017,47 @@ call_allocate(struct rpc_task *task) | |||
937 | rpc_exit(task, -ERESTARTSYS); | 1017 | rpc_exit(task, -ERESTARTSYS); |
938 | } | 1018 | } |
939 | 1019 | ||
1020 | /* | ||
1021 | * 2a. Bind and/or refresh the credentials | ||
1022 | */ | ||
1023 | static void | ||
1024 | call_refresh(struct rpc_task *task) | ||
1025 | { | ||
1026 | dprint_status(task); | ||
1027 | |||
1028 | task->tk_action = call_refreshresult; | ||
1029 | task->tk_status = 0; | ||
1030 | task->tk_client->cl_stats->rpcauthrefresh++; | ||
1031 | rpcauth_refreshcred(task); | ||
1032 | } | ||
1033 | |||
1034 | /* | ||
1035 | * 2b. Process the results of a credential refresh | ||
1036 | */ | ||
1037 | static void | ||
1038 | call_refreshresult(struct rpc_task *task) | ||
1039 | { | ||
1040 | int status = task->tk_status; | ||
1041 | |||
1042 | dprint_status(task); | ||
1043 | |||
1044 | task->tk_status = 0; | ||
1045 | task->tk_action = call_bind; | ||
1046 | if (status >= 0 && rpcauth_uptodatecred(task)) | ||
1047 | return; | ||
1048 | switch (status) { | ||
1049 | case -EACCES: | ||
1050 | rpc_exit(task, -EACCES); | ||
1051 | return; | ||
1052 | case -ENOMEM: | ||
1053 | rpc_exit(task, -ENOMEM); | ||
1054 | return; | ||
1055 | case -ETIMEDOUT: | ||
1056 | rpc_delay(task, 3*HZ); | ||
1057 | } | ||
1058 | task->tk_action = call_refresh; | ||
1059 | } | ||
1060 | |||
940 | static inline int | 1061 | static inline int |
941 | rpc_task_need_encode(struct rpc_task *task) | 1062 | rpc_task_need_encode(struct rpc_task *task) |
942 | { | 1063 | { |
@@ -1472,43 +1593,6 @@ out_retry: | |||
1472 | } | 1593 | } |
1473 | } | 1594 | } |
1474 | 1595 | ||
1475 | /* | ||
1476 | * 8. Refresh the credentials if rejected by the server | ||
1477 | */ | ||
1478 | static void | ||
1479 | call_refresh(struct rpc_task *task) | ||
1480 | { | ||
1481 | dprint_status(task); | ||
1482 | |||
1483 | task->tk_action = call_refreshresult; | ||
1484 | task->tk_status = 0; | ||
1485 | task->tk_client->cl_stats->rpcauthrefresh++; | ||
1486 | rpcauth_refreshcred(task); | ||
1487 | } | ||
1488 | |||
1489 | /* | ||
1490 | * 8a. Process the results of a credential refresh | ||
1491 | */ | ||
1492 | static void | ||
1493 | call_refreshresult(struct rpc_task *task) | ||
1494 | { | ||
1495 | int status = task->tk_status; | ||
1496 | |||
1497 | dprint_status(task); | ||
1498 | |||
1499 | task->tk_status = 0; | ||
1500 | task->tk_action = call_reserve; | ||
1501 | if (status >= 0 && rpcauth_uptodatecred(task)) | ||
1502 | return; | ||
1503 | if (status == -EACCES) { | ||
1504 | rpc_exit(task, -EACCES); | ||
1505 | return; | ||
1506 | } | ||
1507 | task->tk_action = call_refresh; | ||
1508 | if (status != -ETIMEDOUT) | ||
1509 | rpc_delay(task, 3*HZ); | ||
1510 | } | ||
1511 | |||
1512 | static __be32 * | 1596 | static __be32 * |
1513 | rpc_encode_header(struct rpc_task *task) | 1597 | rpc_encode_header(struct rpc_task *task) |
1514 | { | 1598 | { |
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 4a843b883b89..cace6049e4a5 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
@@ -246,17 +246,8 @@ static inline void rpc_task_set_debuginfo(struct rpc_task *task) | |||
246 | 246 | ||
247 | static void rpc_set_active(struct rpc_task *task) | 247 | static void rpc_set_active(struct rpc_task *task) |
248 | { | 248 | { |
249 | struct rpc_clnt *clnt; | ||
250 | if (test_and_set_bit(RPC_TASK_ACTIVE, &task->tk_runstate) != 0) | ||
251 | return; | ||
252 | rpc_task_set_debuginfo(task); | 249 | rpc_task_set_debuginfo(task); |
253 | /* Add to global list of all tasks */ | 250 | set_bit(RPC_TASK_ACTIVE, &task->tk_runstate); |
254 | clnt = task->tk_client; | ||
255 | if (clnt != NULL) { | ||
256 | spin_lock(&clnt->cl_lock); | ||
257 | list_add_tail(&task->tk_task, &clnt->cl_tasks); | ||
258 | spin_unlock(&clnt->cl_lock); | ||
259 | } | ||
260 | } | 251 | } |
261 | 252 | ||
262 | /* | 253 | /* |
@@ -319,11 +310,6 @@ static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, | |||
319 | dprintk("RPC: %5u sleep_on(queue \"%s\" time %lu)\n", | 310 | dprintk("RPC: %5u sleep_on(queue \"%s\" time %lu)\n", |
320 | task->tk_pid, rpc_qname(q), jiffies); | 311 | task->tk_pid, rpc_qname(q), jiffies); |
321 | 312 | ||
322 | if (!RPC_IS_ASYNC(task) && !RPC_IS_ACTIVATED(task)) { | ||
323 | printk(KERN_ERR "RPC: Inactive synchronous task put to sleep!\n"); | ||
324 | return; | ||
325 | } | ||
326 | |||
327 | __rpc_add_wait_queue(q, task); | 313 | __rpc_add_wait_queue(q, task); |
328 | 314 | ||
329 | BUG_ON(task->tk_callback != NULL); | 315 | BUG_ON(task->tk_callback != NULL); |
@@ -334,8 +320,8 @@ static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, | |||
334 | void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, | 320 | void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, |
335 | rpc_action action) | 321 | rpc_action action) |
336 | { | 322 | { |
337 | /* Mark the task as being activated if so needed */ | 323 | /* We shouldn't ever put an inactive task to sleep */ |
338 | rpc_set_active(task); | 324 | BUG_ON(!RPC_IS_ACTIVATED(task)); |
339 | 325 | ||
340 | /* | 326 | /* |
341 | * Protect the queue operations. | 327 | * Protect the queue operations. |
@@ -406,14 +392,6 @@ void rpc_wake_up_queued_task(struct rpc_wait_queue *queue, struct rpc_task *task | |||
406 | EXPORT_SYMBOL_GPL(rpc_wake_up_queued_task); | 392 | EXPORT_SYMBOL_GPL(rpc_wake_up_queued_task); |
407 | 393 | ||
408 | /* | 394 | /* |
409 | * Wake up the specified task | ||
410 | */ | ||
411 | static void rpc_wake_up_task(struct rpc_task *task) | ||
412 | { | ||
413 | rpc_wake_up_queued_task(task->tk_waitqueue, task); | ||
414 | } | ||
415 | |||
416 | /* | ||
417 | * Wake up the next task on a priority queue. | 395 | * Wake up the next task on a priority queue. |
418 | */ | 396 | */ |
419 | static struct rpc_task * __rpc_wake_up_next_priority(struct rpc_wait_queue *queue) | 397 | static struct rpc_task * __rpc_wake_up_next_priority(struct rpc_wait_queue *queue) |
@@ -600,7 +578,15 @@ void rpc_exit_task(struct rpc_task *task) | |||
600 | } | 578 | } |
601 | } | 579 | } |
602 | } | 580 | } |
603 | EXPORT_SYMBOL_GPL(rpc_exit_task); | 581 | |
582 | void rpc_exit(struct rpc_task *task, int status) | ||
583 | { | ||
584 | task->tk_status = status; | ||
585 | task->tk_action = rpc_exit_task; | ||
586 | if (RPC_IS_QUEUED(task)) | ||
587 | rpc_wake_up_queued_task(task->tk_waitqueue, task); | ||
588 | } | ||
589 | EXPORT_SYMBOL_GPL(rpc_exit); | ||
604 | 590 | ||
605 | void rpc_release_calldata(const struct rpc_call_ops *ops, void *calldata) | 591 | void rpc_release_calldata(const struct rpc_call_ops *ops, void *calldata) |
606 | { | 592 | { |
@@ -690,7 +676,6 @@ static void __rpc_execute(struct rpc_task *task) | |||
690 | dprintk("RPC: %5u got signal\n", task->tk_pid); | 676 | dprintk("RPC: %5u got signal\n", task->tk_pid); |
691 | task->tk_flags |= RPC_TASK_KILLED; | 677 | task->tk_flags |= RPC_TASK_KILLED; |
692 | rpc_exit(task, -ERESTARTSYS); | 678 | rpc_exit(task, -ERESTARTSYS); |
693 | rpc_wake_up_task(task); | ||
694 | } | 679 | } |
695 | rpc_set_running(task); | 680 | rpc_set_running(task); |
696 | dprintk("RPC: %5u sync task resuming\n", task->tk_pid); | 681 | dprintk("RPC: %5u sync task resuming\n", task->tk_pid); |
@@ -714,8 +699,9 @@ static void __rpc_execute(struct rpc_task *task) | |||
714 | void rpc_execute(struct rpc_task *task) | 699 | void rpc_execute(struct rpc_task *task) |
715 | { | 700 | { |
716 | rpc_set_active(task); | 701 | rpc_set_active(task); |
717 | rpc_set_running(task); | 702 | rpc_make_runnable(task); |
718 | __rpc_execute(task); | 703 | if (!RPC_IS_ASYNC(task)) |
704 | __rpc_execute(task); | ||
719 | } | 705 | } |
720 | 706 | ||
721 | static void rpc_async_schedule(struct work_struct *work) | 707 | static void rpc_async_schedule(struct work_struct *work) |
@@ -808,26 +794,9 @@ static void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *ta | |||
808 | /* Initialize workqueue for async tasks */ | 794 | /* Initialize workqueue for async tasks */ |
809 | task->tk_workqueue = task_setup_data->workqueue; | 795 | task->tk_workqueue = task_setup_data->workqueue; |
810 | 796 | ||
811 | task->tk_client = task_setup_data->rpc_client; | ||
812 | if (task->tk_client != NULL) { | ||
813 | kref_get(&task->tk_client->cl_kref); | ||
814 | if (task->tk_client->cl_softrtry) | ||
815 | task->tk_flags |= RPC_TASK_SOFT; | ||
816 | } | ||
817 | |||
818 | if (task->tk_ops->rpc_call_prepare != NULL) | 797 | if (task->tk_ops->rpc_call_prepare != NULL) |
819 | task->tk_action = rpc_prepare_task; | 798 | task->tk_action = rpc_prepare_task; |
820 | 799 | ||
821 | if (task_setup_data->rpc_message != NULL) { | ||
822 | task->tk_msg.rpc_proc = task_setup_data->rpc_message->rpc_proc; | ||
823 | task->tk_msg.rpc_argp = task_setup_data->rpc_message->rpc_argp; | ||
824 | task->tk_msg.rpc_resp = task_setup_data->rpc_message->rpc_resp; | ||
825 | /* Bind the user cred */ | ||
826 | rpcauth_bindcred(task, task_setup_data->rpc_message->rpc_cred, task_setup_data->flags); | ||
827 | if (task->tk_action == NULL) | ||
828 | rpc_call_start(task); | ||
829 | } | ||
830 | |||
831 | /* starting timestamp */ | 800 | /* starting timestamp */ |
832 | task->tk_start = ktime_get(); | 801 | task->tk_start = ktime_get(); |
833 | 802 | ||
@@ -896,11 +865,8 @@ void rpc_put_task(struct rpc_task *task) | |||
896 | if (task->tk_rqstp) | 865 | if (task->tk_rqstp) |
897 | xprt_release(task); | 866 | xprt_release(task); |
898 | if (task->tk_msg.rpc_cred) | 867 | if (task->tk_msg.rpc_cred) |
899 | rpcauth_unbindcred(task); | 868 | put_rpccred(task->tk_msg.rpc_cred); |
900 | if (task->tk_client) { | 869 | rpc_task_release_client(task); |
901 | rpc_release_client(task->tk_client); | ||
902 | task->tk_client = NULL; | ||
903 | } | ||
904 | if (task->tk_workqueue != NULL) { | 870 | if (task->tk_workqueue != NULL) { |
905 | INIT_WORK(&task->u.tk_work, rpc_async_release); | 871 | INIT_WORK(&task->u.tk_work, rpc_async_release); |
906 | queue_work(task->tk_workqueue, &task->u.tk_work); | 872 | queue_work(task->tk_workqueue, &task->u.tk_work); |
@@ -913,13 +879,6 @@ static void rpc_release_task(struct rpc_task *task) | |||
913 | { | 879 | { |
914 | dprintk("RPC: %5u release task\n", task->tk_pid); | 880 | dprintk("RPC: %5u release task\n", task->tk_pid); |
915 | 881 | ||
916 | if (!list_empty(&task->tk_task)) { | ||
917 | struct rpc_clnt *clnt = task->tk_client; | ||
918 | /* Remove from client task list */ | ||
919 | spin_lock(&clnt->cl_lock); | ||
920 | list_del(&task->tk_task); | ||
921 | spin_unlock(&clnt->cl_lock); | ||
922 | } | ||
923 | BUG_ON (RPC_IS_QUEUED(task)); | 882 | BUG_ON (RPC_IS_QUEUED(task)); |
924 | 883 | ||
925 | /* Wake up anyone who is waiting for task completion */ | 884 | /* Wake up anyone who is waiting for task completion */ |
@@ -928,35 +887,6 @@ static void rpc_release_task(struct rpc_task *task) | |||
928 | rpc_put_task(task); | 887 | rpc_put_task(task); |
929 | } | 888 | } |
930 | 889 | ||
931 | /* | ||
932 | * Kill all tasks for the given client. | ||
933 | * XXX: kill their descendants as well? | ||
934 | */ | ||
935 | void rpc_killall_tasks(struct rpc_clnt *clnt) | ||
936 | { | ||
937 | struct rpc_task *rovr; | ||
938 | |||
939 | |||
940 | if (list_empty(&clnt->cl_tasks)) | ||
941 | return; | ||
942 | dprintk("RPC: killing all tasks for client %p\n", clnt); | ||
943 | /* | ||
944 | * Spin lock all_tasks to prevent changes... | ||
945 | */ | ||
946 | spin_lock(&clnt->cl_lock); | ||
947 | list_for_each_entry(rovr, &clnt->cl_tasks, tk_task) { | ||
948 | if (! RPC_IS_ACTIVATED(rovr)) | ||
949 | continue; | ||
950 | if (!(rovr->tk_flags & RPC_TASK_KILLED)) { | ||
951 | rovr->tk_flags |= RPC_TASK_KILLED; | ||
952 | rpc_exit(rovr, -EIO); | ||
953 | rpc_wake_up_task(rovr); | ||
954 | } | ||
955 | } | ||
956 | spin_unlock(&clnt->cl_lock); | ||
957 | } | ||
958 | EXPORT_SYMBOL_GPL(rpc_killall_tasks); | ||
959 | |||
960 | int rpciod_up(void) | 890 | int rpciod_up(void) |
961 | { | 891 | { |
962 | return try_module_get(THIS_MODULE) ? 0 : -EINVAL; | 892 | return try_module_get(THIS_MODULE) ? 0 : -EINVAL; |
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index f438347d817b..34b58f9e704a 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c | |||
@@ -33,10 +33,11 @@ init_sunrpc(void) | |||
33 | if (err) | 33 | if (err) |
34 | goto out; | 34 | goto out; |
35 | err = rpc_init_mempool(); | 35 | err = rpc_init_mempool(); |
36 | if (err) { | 36 | if (err) |
37 | unregister_rpc_pipefs(); | 37 | goto out2; |
38 | goto out; | 38 | err = rpcauth_init_module(); |
39 | } | 39 | if (err) |
40 | goto out3; | ||
40 | #ifdef RPC_DEBUG | 41 | #ifdef RPC_DEBUG |
41 | rpc_register_sysctl(); | 42 | rpc_register_sysctl(); |
42 | #endif | 43 | #endif |
@@ -47,7 +48,11 @@ init_sunrpc(void) | |||
47 | cache_register(&unix_gid_cache); | 48 | cache_register(&unix_gid_cache); |
48 | svc_init_xprt_sock(); /* svc sock transport */ | 49 | svc_init_xprt_sock(); /* svc sock transport */ |
49 | init_socket_xprt(); /* clnt sock transport */ | 50 | init_socket_xprt(); /* clnt sock transport */ |
50 | rpcauth_init_module(); | 51 | return 0; |
52 | out3: | ||
53 | rpc_destroy_mempool(); | ||
54 | out2: | ||
55 | unregister_rpc_pipefs(); | ||
51 | out: | 56 | out: |
52 | return err; | 57 | return err; |
53 | } | 58 | } |
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index dcd0132396ba..970fb00f388c 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
@@ -1032,6 +1032,8 @@ void xprt_release(struct rpc_task *task) | |||
1032 | spin_unlock_bh(&xprt->transport_lock); | 1032 | spin_unlock_bh(&xprt->transport_lock); |
1033 | if (req->rq_buffer) | 1033 | if (req->rq_buffer) |
1034 | xprt->ops->buf_free(req->rq_buffer); | 1034 | xprt->ops->buf_free(req->rq_buffer); |
1035 | if (req->rq_cred != NULL) | ||
1036 | put_rpccred(req->rq_cred); | ||
1035 | task->tk_rqstp = NULL; | 1037 | task->tk_rqstp = NULL; |
1036 | if (req->rq_release_snd_buf) | 1038 | if (req->rq_release_snd_buf) |
1037 | req->rq_release_snd_buf(req); | 1039 | req->rq_release_snd_buf(req); |
@@ -1129,6 +1131,7 @@ static void xprt_destroy(struct kref *kref) | |||
1129 | rpc_destroy_wait_queue(&xprt->sending); | 1131 | rpc_destroy_wait_queue(&xprt->sending); |
1130 | rpc_destroy_wait_queue(&xprt->resend); | 1132 | rpc_destroy_wait_queue(&xprt->resend); |
1131 | rpc_destroy_wait_queue(&xprt->backlog); | 1133 | rpc_destroy_wait_queue(&xprt->backlog); |
1134 | cancel_work_sync(&xprt->task_cleanup); | ||
1132 | /* | 1135 | /* |
1133 | * Tear down transport state and free the rpc_xprt | 1136 | * Tear down transport state and free the rpc_xprt |
1134 | */ | 1137 | */ |