diff options
Diffstat (limited to 'fs/nfs/nfs4state.c')
| -rw-r--r-- | fs/nfs/nfs4state.c | 175 |
1 files changed, 20 insertions, 155 deletions
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 96e5b82c153b..5fffbdfa971f 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
| @@ -38,7 +38,6 @@ | |||
| 38 | * subsequent patch. | 38 | * subsequent patch. |
| 39 | */ | 39 | */ |
| 40 | 40 | ||
| 41 | #include <linux/config.h> | ||
| 42 | #include <linux/slab.h> | 41 | #include <linux/slab.h> |
| 43 | #include <linux/smp_lock.h> | 42 | #include <linux/smp_lock.h> |
| 44 | #include <linux/nfs_fs.h> | 43 | #include <linux/nfs_fs.h> |
| @@ -51,149 +50,15 @@ | |||
| 51 | #include "nfs4_fs.h" | 50 | #include "nfs4_fs.h" |
| 52 | #include "callback.h" | 51 | #include "callback.h" |
| 53 | #include "delegation.h" | 52 | #include "delegation.h" |
| 53 | #include "internal.h" | ||
| 54 | 54 | ||
| 55 | #define OPENOWNER_POOL_SIZE 8 | 55 | #define OPENOWNER_POOL_SIZE 8 |
| 56 | 56 | ||
| 57 | const nfs4_stateid zero_stateid; | 57 | const nfs4_stateid zero_stateid; |
| 58 | 58 | ||
| 59 | static DEFINE_SPINLOCK(state_spinlock); | ||
| 60 | static LIST_HEAD(nfs4_clientid_list); | 59 | static LIST_HEAD(nfs4_clientid_list); |
| 61 | 60 | ||
| 62 | void | 61 | static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred) |
| 63 | init_nfsv4_state(struct nfs_server *server) | ||
| 64 | { | ||
| 65 | server->nfs4_state = NULL; | ||
| 66 | INIT_LIST_HEAD(&server->nfs4_siblings); | ||
| 67 | } | ||
| 68 | |||
| 69 | void | ||
| 70 | destroy_nfsv4_state(struct nfs_server *server) | ||
| 71 | { | ||
| 72 | kfree(server->mnt_path); | ||
| 73 | server->mnt_path = NULL; | ||
| 74 | if (server->nfs4_state) { | ||
| 75 | nfs4_put_client(server->nfs4_state); | ||
| 76 | server->nfs4_state = NULL; | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | /* | ||
| 81 | * nfs4_get_client(): returns an empty client structure | ||
| 82 | * nfs4_put_client(): drops reference to client structure | ||
| 83 | * | ||
| 84 | * Since these are allocated/deallocated very rarely, we don't | ||
| 85 | * bother putting them in a slab cache... | ||
| 86 | */ | ||
| 87 | static struct nfs4_client * | ||
| 88 | nfs4_alloc_client(struct in_addr *addr) | ||
| 89 | { | ||
| 90 | struct nfs4_client *clp; | ||
| 91 | |||
| 92 | if (nfs_callback_up() < 0) | ||
| 93 | return NULL; | ||
| 94 | if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) { | ||
| 95 | nfs_callback_down(); | ||
| 96 | return NULL; | ||
| 97 | } | ||
| 98 | memcpy(&clp->cl_addr, addr, sizeof(clp->cl_addr)); | ||
| 99 | init_rwsem(&clp->cl_sem); | ||
| 100 | INIT_LIST_HEAD(&clp->cl_delegations); | ||
| 101 | INIT_LIST_HEAD(&clp->cl_state_owners); | ||
| 102 | INIT_LIST_HEAD(&clp->cl_unused); | ||
| 103 | spin_lock_init(&clp->cl_lock); | ||
| 104 | atomic_set(&clp->cl_count, 1); | ||
| 105 | INIT_WORK(&clp->cl_renewd, nfs4_renew_state, clp); | ||
| 106 | INIT_LIST_HEAD(&clp->cl_superblocks); | ||
| 107 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client"); | ||
| 108 | clp->cl_rpcclient = ERR_PTR(-EINVAL); | ||
| 109 | clp->cl_boot_time = CURRENT_TIME; | ||
| 110 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; | ||
| 111 | return clp; | ||
| 112 | } | ||
| 113 | |||
| 114 | static void | ||
| 115 | nfs4_free_client(struct nfs4_client *clp) | ||
| 116 | { | ||
| 117 | struct nfs4_state_owner *sp; | ||
| 118 | |||
| 119 | while (!list_empty(&clp->cl_unused)) { | ||
| 120 | sp = list_entry(clp->cl_unused.next, | ||
| 121 | struct nfs4_state_owner, | ||
| 122 | so_list); | ||
| 123 | list_del(&sp->so_list); | ||
| 124 | kfree(sp); | ||
| 125 | } | ||
| 126 | BUG_ON(!list_empty(&clp->cl_state_owners)); | ||
| 127 | nfs_idmap_delete(clp); | ||
| 128 | if (!IS_ERR(clp->cl_rpcclient)) | ||
| 129 | rpc_shutdown_client(clp->cl_rpcclient); | ||
| 130 | kfree(clp); | ||
| 131 | nfs_callback_down(); | ||
| 132 | } | ||
| 133 | |||
| 134 | static struct nfs4_client *__nfs4_find_client(struct in_addr *addr) | ||
| 135 | { | ||
| 136 | struct nfs4_client *clp; | ||
| 137 | list_for_each_entry(clp, &nfs4_clientid_list, cl_servers) { | ||
| 138 | if (memcmp(&clp->cl_addr, addr, sizeof(clp->cl_addr)) == 0) { | ||
| 139 | atomic_inc(&clp->cl_count); | ||
| 140 | return clp; | ||
| 141 | } | ||
| 142 | } | ||
| 143 | return NULL; | ||
| 144 | } | ||
| 145 | |||
| 146 | struct nfs4_client *nfs4_find_client(struct in_addr *addr) | ||
| 147 | { | ||
| 148 | struct nfs4_client *clp; | ||
| 149 | spin_lock(&state_spinlock); | ||
| 150 | clp = __nfs4_find_client(addr); | ||
| 151 | spin_unlock(&state_spinlock); | ||
| 152 | return clp; | ||
| 153 | } | ||
| 154 | |||
| 155 | struct nfs4_client * | ||
| 156 | nfs4_get_client(struct in_addr *addr) | ||
| 157 | { | ||
| 158 | struct nfs4_client *clp, *new = NULL; | ||
| 159 | |||
| 160 | spin_lock(&state_spinlock); | ||
| 161 | for (;;) { | ||
| 162 | clp = __nfs4_find_client(addr); | ||
| 163 | if (clp != NULL) | ||
| 164 | break; | ||
| 165 | clp = new; | ||
| 166 | if (clp != NULL) { | ||
| 167 | list_add(&clp->cl_servers, &nfs4_clientid_list); | ||
| 168 | new = NULL; | ||
| 169 | break; | ||
| 170 | } | ||
| 171 | spin_unlock(&state_spinlock); | ||
| 172 | new = nfs4_alloc_client(addr); | ||
| 173 | spin_lock(&state_spinlock); | ||
| 174 | if (new == NULL) | ||
| 175 | break; | ||
| 176 | } | ||
| 177 | spin_unlock(&state_spinlock); | ||
| 178 | if (new) | ||
| 179 | nfs4_free_client(new); | ||
| 180 | return clp; | ||
| 181 | } | ||
| 182 | |||
| 183 | void | ||
| 184 | nfs4_put_client(struct nfs4_client *clp) | ||
| 185 | { | ||
| 186 | if (!atomic_dec_and_lock(&clp->cl_count, &state_spinlock)) | ||
| 187 | return; | ||
| 188 | list_del(&clp->cl_servers); | ||
| 189 | spin_unlock(&state_spinlock); | ||
| 190 | BUG_ON(!list_empty(&clp->cl_superblocks)); | ||
| 191 | rpc_wake_up(&clp->cl_rpcwaitq); | ||
| 192 | nfs4_kill_renewd(clp); | ||
| 193 | nfs4_free_client(clp); | ||
| 194 | } | ||
| 195 | |||
| 196 | static int nfs4_init_client(struct nfs4_client *clp, struct rpc_cred *cred) | ||
| 197 | { | 62 | { |
| 198 | int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, | 63 | int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, |
| 199 | nfs_callback_tcpport, cred); | 64 | nfs_callback_tcpport, cred); |
| @@ -205,13 +70,13 @@ static int nfs4_init_client(struct nfs4_client *clp, struct rpc_cred *cred) | |||
| 205 | } | 70 | } |
| 206 | 71 | ||
| 207 | u32 | 72 | u32 |
| 208 | nfs4_alloc_lockowner_id(struct nfs4_client *clp) | 73 | nfs4_alloc_lockowner_id(struct nfs_client *clp) |
| 209 | { | 74 | { |
| 210 | return clp->cl_lockowner_id ++; | 75 | return clp->cl_lockowner_id ++; |
| 211 | } | 76 | } |
| 212 | 77 | ||
| 213 | static struct nfs4_state_owner * | 78 | static struct nfs4_state_owner * |
| 214 | nfs4_client_grab_unused(struct nfs4_client *clp, struct rpc_cred *cred) | 79 | nfs4_client_grab_unused(struct nfs_client *clp, struct rpc_cred *cred) |
| 215 | { | 80 | { |
| 216 | struct nfs4_state_owner *sp = NULL; | 81 | struct nfs4_state_owner *sp = NULL; |
| 217 | 82 | ||
| @@ -225,7 +90,7 @@ nfs4_client_grab_unused(struct nfs4_client *clp, struct rpc_cred *cred) | |||
| 225 | return sp; | 90 | return sp; |
| 226 | } | 91 | } |
| 227 | 92 | ||
| 228 | struct rpc_cred *nfs4_get_renew_cred(struct nfs4_client *clp) | 93 | struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp) |
| 229 | { | 94 | { |
| 230 | struct nfs4_state_owner *sp; | 95 | struct nfs4_state_owner *sp; |
| 231 | struct rpc_cred *cred = NULL; | 96 | struct rpc_cred *cred = NULL; |
| @@ -239,7 +104,7 @@ struct rpc_cred *nfs4_get_renew_cred(struct nfs4_client *clp) | |||
| 239 | return cred; | 104 | return cred; |
| 240 | } | 105 | } |
| 241 | 106 | ||
| 242 | struct rpc_cred *nfs4_get_setclientid_cred(struct nfs4_client *clp) | 107 | struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp) |
| 243 | { | 108 | { |
| 244 | struct nfs4_state_owner *sp; | 109 | struct nfs4_state_owner *sp; |
| 245 | 110 | ||
| @@ -252,7 +117,7 @@ struct rpc_cred *nfs4_get_setclientid_cred(struct nfs4_client *clp) | |||
| 252 | } | 117 | } |
| 253 | 118 | ||
| 254 | static struct nfs4_state_owner * | 119 | static struct nfs4_state_owner * |
| 255 | nfs4_find_state_owner(struct nfs4_client *clp, struct rpc_cred *cred) | 120 | nfs4_find_state_owner(struct nfs_client *clp, struct rpc_cred *cred) |
| 256 | { | 121 | { |
| 257 | struct nfs4_state_owner *sp, *res = NULL; | 122 | struct nfs4_state_owner *sp, *res = NULL; |
| 258 | 123 | ||
| @@ -295,7 +160,7 @@ nfs4_alloc_state_owner(void) | |||
| 295 | void | 160 | void |
| 296 | nfs4_drop_state_owner(struct nfs4_state_owner *sp) | 161 | nfs4_drop_state_owner(struct nfs4_state_owner *sp) |
| 297 | { | 162 | { |
| 298 | struct nfs4_client *clp = sp->so_client; | 163 | struct nfs_client *clp = sp->so_client; |
| 299 | spin_lock(&clp->cl_lock); | 164 | spin_lock(&clp->cl_lock); |
| 300 | list_del_init(&sp->so_list); | 165 | list_del_init(&sp->so_list); |
| 301 | spin_unlock(&clp->cl_lock); | 166 | spin_unlock(&clp->cl_lock); |
| @@ -307,7 +172,7 @@ nfs4_drop_state_owner(struct nfs4_state_owner *sp) | |||
| 307 | */ | 172 | */ |
| 308 | struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct rpc_cred *cred) | 173 | struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct rpc_cred *cred) |
| 309 | { | 174 | { |
| 310 | struct nfs4_client *clp = server->nfs4_state; | 175 | struct nfs_client *clp = server->nfs_client; |
| 311 | struct nfs4_state_owner *sp, *new; | 176 | struct nfs4_state_owner *sp, *new; |
| 312 | 177 | ||
| 313 | get_rpccred(cred); | 178 | get_rpccred(cred); |
| @@ -338,7 +203,7 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct | |||
| 338 | */ | 203 | */ |
| 339 | void nfs4_put_state_owner(struct nfs4_state_owner *sp) | 204 | void nfs4_put_state_owner(struct nfs4_state_owner *sp) |
| 340 | { | 205 | { |
| 341 | struct nfs4_client *clp = sp->so_client; | 206 | struct nfs_client *clp = sp->so_client; |
| 342 | struct rpc_cred *cred = sp->so_cred; | 207 | struct rpc_cred *cred = sp->so_cred; |
| 343 | 208 | ||
| 344 | if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock)) | 209 | if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock)) |
| @@ -541,7 +406,7 @@ __nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) | |||
| 541 | static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) | 406 | static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) |
| 542 | { | 407 | { |
| 543 | struct nfs4_lock_state *lsp; | 408 | struct nfs4_lock_state *lsp; |
| 544 | struct nfs4_client *clp = state->owner->so_client; | 409 | struct nfs_client *clp = state->owner->so_client; |
| 545 | 410 | ||
| 546 | lsp = kzalloc(sizeof(*lsp), GFP_KERNEL); | 411 | lsp = kzalloc(sizeof(*lsp), GFP_KERNEL); |
| 547 | if (lsp == NULL) | 412 | if (lsp == NULL) |
| @@ -753,7 +618,7 @@ out: | |||
| 753 | 618 | ||
| 754 | static int reclaimer(void *); | 619 | static int reclaimer(void *); |
| 755 | 620 | ||
| 756 | static inline void nfs4_clear_recover_bit(struct nfs4_client *clp) | 621 | static inline void nfs4_clear_recover_bit(struct nfs_client *clp) |
| 757 | { | 622 | { |
| 758 | smp_mb__before_clear_bit(); | 623 | smp_mb__before_clear_bit(); |
| 759 | clear_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state); | 624 | clear_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state); |
| @@ -765,25 +630,25 @@ static inline void nfs4_clear_recover_bit(struct nfs4_client *clp) | |||
| 765 | /* | 630 | /* |
| 766 | * State recovery routine | 631 | * State recovery routine |
| 767 | */ | 632 | */ |
| 768 | static void nfs4_recover_state(struct nfs4_client *clp) | 633 | static void nfs4_recover_state(struct nfs_client *clp) |
| 769 | { | 634 | { |
| 770 | struct task_struct *task; | 635 | struct task_struct *task; |
| 771 | 636 | ||
| 772 | __module_get(THIS_MODULE); | 637 | __module_get(THIS_MODULE); |
| 773 | atomic_inc(&clp->cl_count); | 638 | atomic_inc(&clp->cl_count); |
| 774 | task = kthread_run(reclaimer, clp, "%u.%u.%u.%u-reclaim", | 639 | task = kthread_run(reclaimer, clp, "%u.%u.%u.%u-reclaim", |
| 775 | NIPQUAD(clp->cl_addr)); | 640 | NIPQUAD(clp->cl_addr.sin_addr)); |
| 776 | if (!IS_ERR(task)) | 641 | if (!IS_ERR(task)) |
| 777 | return; | 642 | return; |
| 778 | nfs4_clear_recover_bit(clp); | 643 | nfs4_clear_recover_bit(clp); |
| 779 | nfs4_put_client(clp); | 644 | nfs_put_client(clp); |
| 780 | module_put(THIS_MODULE); | 645 | module_put(THIS_MODULE); |
| 781 | } | 646 | } |
| 782 | 647 | ||
| 783 | /* | 648 | /* |
| 784 | * Schedule a state recovery attempt | 649 | * Schedule a state recovery attempt |
| 785 | */ | 650 | */ |
| 786 | void nfs4_schedule_state_recovery(struct nfs4_client *clp) | 651 | void nfs4_schedule_state_recovery(struct nfs_client *clp) |
| 787 | { | 652 | { |
| 788 | if (!clp) | 653 | if (!clp) |
| 789 | return; | 654 | return; |
| @@ -880,7 +745,7 @@ out_err: | |||
| 880 | return status; | 745 | return status; |
| 881 | } | 746 | } |
| 882 | 747 | ||
| 883 | static void nfs4_state_mark_reclaim(struct nfs4_client *clp) | 748 | static void nfs4_state_mark_reclaim(struct nfs_client *clp) |
| 884 | { | 749 | { |
| 885 | struct nfs4_state_owner *sp; | 750 | struct nfs4_state_owner *sp; |
| 886 | struct nfs4_state *state; | 751 | struct nfs4_state *state; |
| @@ -904,7 +769,7 @@ static void nfs4_state_mark_reclaim(struct nfs4_client *clp) | |||
| 904 | 769 | ||
| 905 | static int reclaimer(void *ptr) | 770 | static int reclaimer(void *ptr) |
| 906 | { | 771 | { |
| 907 | struct nfs4_client *clp = ptr; | 772 | struct nfs_client *clp = ptr; |
| 908 | struct nfs4_state_owner *sp; | 773 | struct nfs4_state_owner *sp; |
| 909 | struct nfs4_state_recovery_ops *ops; | 774 | struct nfs4_state_recovery_ops *ops; |
| 910 | struct rpc_cred *cred; | 775 | struct rpc_cred *cred; |
| @@ -971,12 +836,12 @@ out: | |||
| 971 | if (status == -NFS4ERR_CB_PATH_DOWN) | 836 | if (status == -NFS4ERR_CB_PATH_DOWN) |
| 972 | nfs_handle_cb_pathdown(clp); | 837 | nfs_handle_cb_pathdown(clp); |
| 973 | nfs4_clear_recover_bit(clp); | 838 | nfs4_clear_recover_bit(clp); |
| 974 | nfs4_put_client(clp); | 839 | nfs_put_client(clp); |
| 975 | module_put_and_exit(0); | 840 | module_put_and_exit(0); |
| 976 | return 0; | 841 | return 0; |
| 977 | out_error: | 842 | out_error: |
| 978 | printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u with error %d\n", | 843 | printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u with error %d\n", |
| 979 | NIPQUAD(clp->cl_addr.s_addr), -status); | 844 | NIPQUAD(clp->cl_addr.sin_addr), -status); |
| 980 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 845 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); |
| 981 | goto out; | 846 | goto out; |
| 982 | } | 847 | } |
